Merge branch 'develop' into sunny/coins-AllGT-test
This commit is contained in:
commit
997aa6106c
|
@ -35,7 +35,7 @@ set_macos_env: &macos_env
|
|||
docs_update: &docs_deploy
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: tendermint/docs_deployment
|
||||
- image: tendermintdev/jq_curl
|
||||
environment:
|
||||
AWS_REGION: us-east-1
|
||||
|
||||
|
@ -280,7 +280,22 @@ jobs:
|
|||
- run:
|
||||
name: Trigger website build
|
||||
command: |
|
||||
chamber exec cosmos-sdk -- start_website_build
|
||||
curl --silent \
|
||||
--show-error \
|
||||
-X POST \
|
||||
--header "Content-Type: application/json" \
|
||||
-d "{\"branch\": \"$CIRCLE_BRANCH\"}" \
|
||||
"https://circleci.com/api/v1.1/project/github/$CIRCLE_PROJECT_USERNAME/$WEBSITE_REPO_NAME/build?circle-token=$TENDERBOT_API_TOKEN" > response.json
|
||||
|
||||
RESULT=`jq -r '.status' response.json`
|
||||
MESSAGE=`jq -r '.message' response.json`
|
||||
|
||||
if [[ ${RESULT} == "null" ]] || [[ ${RESULT} -ne "200" ]]; then
|
||||
echo "CircleCI API call failed: $MESSAGE"
|
||||
exit 1
|
||||
else
|
||||
echo "Website build started"
|
||||
fi
|
||||
|
||||
macos_ci:
|
||||
<<: *macos_defaults
|
||||
|
@ -378,7 +393,12 @@ workflows:
|
|||
only:
|
||||
- master
|
||||
- develop
|
||||
- setup_dependencies
|
||||
- setup_dependencies:
|
||||
# filters here are needed to enable this job also for tags
|
||||
filters:
|
||||
tags:
|
||||
only:
|
||||
- /^v.*/
|
||||
- lint:
|
||||
requires:
|
||||
- setup_dependencies
|
||||
|
|
10
PENDING.md
10
PENDING.md
|
@ -39,6 +39,8 @@
|
|||
|
||||
### Gaia CLI
|
||||
|
||||
* [\#3859](https://github.com/cosmos/cosmos-sdk/pull/3859) Add newline to echo of `gaiacli keys ...`
|
||||
|
||||
### Gaia
|
||||
|
||||
* #3808 `gaiad` and `gaiacli` integration tests use ./build/ binaries.
|
||||
|
@ -46,9 +48,14 @@
|
|||
### SDK
|
||||
|
||||
* [\#3820] Make Coins.IsAllGT() more robust and consistent.
|
||||
* #3801 `baseapp` saftey improvements
|
||||
|
||||
### Tendermint
|
||||
|
||||
### CI/CD
|
||||
|
||||
* [\198](https://github.com/cosmos/cosmos-sdk/pull/3832)
|
||||
|
||||
<!--------------------------------- BUG FIXES -------------------------------->
|
||||
|
||||
## BUG FIXES
|
||||
|
@ -61,4 +68,7 @@
|
|||
|
||||
### SDK
|
||||
|
||||
* [\#3837] Fix `WithdrawValidatorCommission` to properly set the validator's
|
||||
remaining commission.
|
||||
|
||||
### Tendermint
|
||||
|
|
|
@ -287,12 +287,25 @@ func (app *BaseApp) storeConsensusParams(consensusParams *abci.ConsensusParams)
|
|||
mainStore.Set(mainConsensusParamsKey, consensusParamsBz)
|
||||
}
|
||||
|
||||
// getMaximumBlockGas gets the maximum gas from the consensus params.
|
||||
func (app *BaseApp) getMaximumBlockGas() (maxGas uint64) {
|
||||
// getMaximumBlockGas gets the maximum gas from the consensus params. It panics
|
||||
// if maximum block gas is less than negative one and returns zero if negative
|
||||
// one.
|
||||
func (app *BaseApp) getMaximumBlockGas() uint64 {
|
||||
if app.consensusParams == nil || app.consensusParams.BlockSize == nil {
|
||||
return 0
|
||||
}
|
||||
return uint64(app.consensusParams.BlockSize.MaxGas)
|
||||
|
||||
maxGas := app.consensusParams.BlockSize.MaxGas
|
||||
switch {
|
||||
case maxGas < -1:
|
||||
panic(fmt.Sprintf("invalid maximum block gas: %d", maxGas))
|
||||
|
||||
case maxGas == -1:
|
||||
return 0
|
||||
|
||||
default:
|
||||
return uint64(maxGas)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -510,6 +523,19 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) (res
|
|||
}
|
||||
}
|
||||
|
||||
func (app *BaseApp) validateHeight(req abci.RequestBeginBlock) error {
|
||||
if req.Header.Height < 1 {
|
||||
return fmt.Errorf("invalid height: %d", req.Header.Height)
|
||||
}
|
||||
|
||||
prevHeight := app.LastBlockHeight()
|
||||
if req.Header.Height != prevHeight+1 {
|
||||
return fmt.Errorf("invalid height: %d; expected: %d", req.Header.Height, prevHeight+1)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// BeginBlock implements the ABCI application interface.
|
||||
func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) {
|
||||
if app.cms.TracingEnabled() {
|
||||
|
@ -518,6 +544,10 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg
|
|||
))
|
||||
}
|
||||
|
||||
if err := app.validateHeight(req); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Initialize the DeliverTx state. If this is the first block, it should
|
||||
// already be initialized in InitChain. Otherwise app.deliverState will be
|
||||
// nil, since it is reset on Commit.
|
||||
|
|
|
@ -296,6 +296,7 @@ func TestInitChainer(t *testing.T) {
|
|||
// stores are mounted and private members are set - sealing baseapp
|
||||
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(0), app.LastBlockHeight())
|
||||
|
||||
app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}"), ChainId: "test-chain-id"}) // must have valid JSON genesis file, even if empty
|
||||
|
||||
|
@ -308,6 +309,7 @@ func TestInitChainer(t *testing.T) {
|
|||
|
||||
app.Commit()
|
||||
res = app.Query(query)
|
||||
require.Equal(t, int64(1), app.LastBlockHeight())
|
||||
require.Equal(t, value, res.Value)
|
||||
|
||||
// reload app
|
||||
|
@ -316,14 +318,17 @@ func TestInitChainer(t *testing.T) {
|
|||
app.MountStores(capKey, capKey2)
|
||||
err = app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, int64(1), app.LastBlockHeight())
|
||||
|
||||
// ensure we can still query after reloading
|
||||
res = app.Query(query)
|
||||
require.Equal(t, value, res.Value)
|
||||
|
||||
// commit and ensure we can still query
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
header := abci.Header{Height: app.LastBlockHeight() + 1}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
app.Commit()
|
||||
|
||||
res = app.Query(query)
|
||||
require.Equal(t, value, res.Value)
|
||||
}
|
||||
|
@ -514,7 +519,6 @@ func TestCheckTx(t *testing.T) {
|
|||
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||
|
||||
nTxs := int64(5)
|
||||
|
||||
app.InitChain(abci.RequestInitChain{})
|
||||
|
||||
// Create same codec used in txDecoder
|
||||
|
@ -536,7 +540,8 @@ func TestCheckTx(t *testing.T) {
|
|||
require.Equal(t, nTxs, storedCounter)
|
||||
|
||||
// If a block is committed, CheckTx state should be reset.
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
header := abci.Header{Height: 1}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
app.EndBlock(abci.RequestEndBlock{})
|
||||
app.Commit()
|
||||
|
||||
|
@ -567,16 +572,22 @@ func TestDeliverTx(t *testing.T) {
|
|||
|
||||
nBlocks := 3
|
||||
txPerHeight := 5
|
||||
|
||||
for blockN := 0; blockN < nBlocks; blockN++ {
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
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(txBytes)
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
}
|
||||
|
||||
app.EndBlock(abci.RequestEndBlock{})
|
||||
app.Commit()
|
||||
}
|
||||
|
@ -610,48 +621,47 @@ func TestMultiMsgDeliverTx(t *testing.T) {
|
|||
|
||||
// run a multi-msg tx
|
||||
// with all msgs the same route
|
||||
{
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
tx := newTxCounter(0, 0, 1, 2)
|
||||
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
||||
require.NoError(t, err)
|
||||
res := app.DeliverTx(txBytes)
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
|
||||
store := app.deliverState.ctx.KVStore(capKey1)
|
||||
header := abci.Header{Height: 1}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
tx := newTxCounter(0, 0, 1, 2)
|
||||
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
||||
require.NoError(t, err)
|
||||
res := app.DeliverTx(txBytes)
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
|
||||
// tx counter only incremented once
|
||||
txCounter := getIntFromStore(store, anteKey)
|
||||
require.Equal(t, int64(1), txCounter)
|
||||
store := app.deliverState.ctx.KVStore(capKey1)
|
||||
|
||||
// msg counter incremented three times
|
||||
msgCounter := getIntFromStore(store, deliverKey)
|
||||
require.Equal(t, int64(3), msgCounter)
|
||||
}
|
||||
// tx counter only incremented once
|
||||
txCounter := getIntFromStore(store, anteKey)
|
||||
require.Equal(t, int64(1), txCounter)
|
||||
|
||||
// msg counter incremented three times
|
||||
msgCounter := getIntFromStore(store, deliverKey)
|
||||
require.Equal(t, int64(3), msgCounter)
|
||||
|
||||
// replace the second message with a msgCounter2
|
||||
{
|
||||
tx := newTxCounter(1, 3)
|
||||
tx.Msgs = append(tx.Msgs, msgCounter2{0})
|
||||
tx.Msgs = append(tx.Msgs, msgCounter2{1})
|
||||
txBytes, err := codec.MarshalBinaryLengthPrefixed(tx)
|
||||
require.NoError(t, err)
|
||||
res := app.DeliverTx(txBytes)
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
|
||||
store := app.deliverState.ctx.KVStore(capKey1)
|
||||
tx = newTxCounter(1, 3)
|
||||
tx.Msgs = append(tx.Msgs, msgCounter2{0})
|
||||
tx.Msgs = append(tx.Msgs, msgCounter2{1})
|
||||
txBytes, err = codec.MarshalBinaryLengthPrefixed(tx)
|
||||
require.NoError(t, err)
|
||||
res = app.DeliverTx(txBytes)
|
||||
require.True(t, res.IsOK(), fmt.Sprintf("%v", res))
|
||||
|
||||
// tx counter only incremented once
|
||||
txCounter := getIntFromStore(store, anteKey)
|
||||
require.Equal(t, int64(2), txCounter)
|
||||
store = app.deliverState.ctx.KVStore(capKey1)
|
||||
|
||||
// original counter increments by one
|
||||
// new counter increments by two
|
||||
msgCounter := getIntFromStore(store, deliverKey)
|
||||
require.Equal(t, int64(4), msgCounter)
|
||||
msgCounter2 := getIntFromStore(store, deliverKey2)
|
||||
require.Equal(t, int64(2), msgCounter2)
|
||||
}
|
||||
// tx counter only incremented once
|
||||
txCounter = getIntFromStore(store, anteKey)
|
||||
require.Equal(t, int64(2), txCounter)
|
||||
|
||||
// original counter increments by one
|
||||
// new counter increments by two
|
||||
msgCounter = getIntFromStore(store, deliverKey)
|
||||
require.Equal(t, int64(4), msgCounter)
|
||||
msgCounter2 := getIntFromStore(store, deliverKey2)
|
||||
require.Equal(t, int64(2), msgCounter2)
|
||||
}
|
||||
|
||||
// Interleave calls to Check and Deliver and ensure
|
||||
|
@ -692,7 +702,8 @@ func TestSimulateTx(t *testing.T) {
|
|||
nBlocks := 3
|
||||
for blockN := 0; blockN < nBlocks; blockN++ {
|
||||
count := int64(blockN + 1)
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
header := abci.Header{Height: count}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
tx := newTxCounter(count, count)
|
||||
txBytes, err := cdc.MarshalBinaryLengthPrefixed(tx)
|
||||
|
@ -737,7 +748,9 @@ func TestRunInvalidTransaction(t *testing.T) {
|
|||
}
|
||||
|
||||
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: 1}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
// Transaction with no messages
|
||||
{
|
||||
|
@ -847,7 +860,8 @@ func TestTxGasLimits(t *testing.T) {
|
|||
|
||||
app := setupBaseApp(t, anteOpt, routerOpt)
|
||||
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
header := abci.Header{Height: 1}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
testCases := []struct {
|
||||
tx *txTest
|
||||
|
@ -962,7 +976,8 @@ func TestMaxBlockGasLimits(t *testing.T) {
|
|||
tx := tc.tx
|
||||
|
||||
// reset the block gas
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
header := abci.Header{Height: app.LastBlockHeight() + 1}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
// execute the transaction multiple times
|
||||
for j := 0; j < tc.numDelivers; j++ {
|
||||
|
@ -1005,7 +1020,9 @@ func TestBaseAppAnteHandler(t *testing.T) {
|
|||
|
||||
app.InitChain(abci.RequestInitChain{})
|
||||
registerTestCodec(cdc)
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: app.LastBlockHeight() + 1}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
// execute a tx that will fail ante handler execution
|
||||
//
|
||||
|
@ -1112,7 +1129,9 @@ func TestGasConsumptionBadTx(t *testing.T) {
|
|||
})
|
||||
|
||||
app.InitChain(abci.RequestInitChain{})
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: app.LastBlockHeight() + 1}
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
tx := newTxCounter(5, 0)
|
||||
tx.setFailOnAnte(true)
|
||||
|
@ -1174,7 +1193,9 @@ func TestQuery(t *testing.T) {
|
|||
require.Equal(t, 0, len(res.Value))
|
||||
|
||||
// query is still empty after a DeliverTx before we commit
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
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))
|
||||
res = app.Query(query)
|
||||
|
@ -1216,3 +1237,19 @@ func TestP2PQuery(t *testing.T) {
|
|||
res = app.Query(idQuery)
|
||||
require.Equal(t, uint32(4), res.Code)
|
||||
}
|
||||
|
||||
func TestGetMaximumBlockGas(t *testing.T) {
|
||||
app := setupBaseApp(t)
|
||||
|
||||
app.setConsensusParams(&abci.ConsensusParams{BlockSize: &abci.BlockSizeParams{MaxGas: 0}})
|
||||
require.Equal(t, uint64(0), app.getMaximumBlockGas())
|
||||
|
||||
app.setConsensusParams(&abci.ConsensusParams{BlockSize: &abci.BlockSizeParams{MaxGas: -1}})
|
||||
require.Equal(t, uint64(0), app.getMaximumBlockGas())
|
||||
|
||||
app.setConsensusParams(&abci.ConsensusParams{BlockSize: &abci.BlockSizeParams{MaxGas: 5000000}})
|
||||
require.Equal(t, uint64(5000000), app.getMaximumBlockGas())
|
||||
|
||||
app.setConsensusParams(&abci.ConsensusParams{BlockSize: &abci.BlockSizeParams{MaxGas: -5000000}})
|
||||
require.Panics(t, func() { app.getMaximumBlockGas() })
|
||||
}
|
||||
|
|
|
@ -259,7 +259,7 @@ func (ctx CLIContext) PrintOutput(toPrint fmt.Stringer) (err error) {
|
|||
|
||||
case "json":
|
||||
if ctx.Indent {
|
||||
out, err = ctx.Codec.MarshalJSONIndent(toPrint, "", " ")
|
||||
out, err = ctx.Codec.MarshalJSONIndent(toPrint, "", " ")
|
||||
} else {
|
||||
out, err = ctx.Codec.MarshalJSON(toPrint)
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ func runAddCmd(_ *cobra.Command, args []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, "Key %q saved to disk.", name)
|
||||
fmt.Fprintf(os.Stderr, "Key %q saved to disk.\n", name)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -216,7 +216,7 @@ func runAddCmd(_ *cobra.Command, args []string) error {
|
|||
}
|
||||
|
||||
if !bip39.IsMnemonicValid(mnemonic) {
|
||||
fmt.Fprintf(os.Stderr, "Error: Mnemonic is not valid")
|
||||
fmt.Fprintf(os.Stderr, "Error: Mnemonic is not valid.\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) {
|
|||
printKeyTextHeader()
|
||||
printKeyOutput(ko)
|
||||
|
||||
case "json":
|
||||
case OutputFormatJSON:
|
||||
out, err := MarshalJSON(ko)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
@ -61,34 +61,7 @@ Build tags indicate special features that have been enabled in the binary.
|
|||
|
||||
### Install binary distribution via snap (Linux only)
|
||||
|
||||
Gaia can be installed on various GNU/Linux distributions from the [Snapcraft.io](https://snapcraft.io/gaia) store:
|
||||
|
||||
```bash
|
||||
$ sudo snap install gaia
|
||||
```
|
||||
|
||||
Development builds are available through the `edge` channel:
|
||||
|
||||
```bash
|
||||
$ sudo snap install --edge gaia
|
||||
```
|
||||
|
||||
::: tip
|
||||
At the time of writing, only the following [architectures are supported](https://build.snapcraft.io/user/cosmos/cosmos-sdk): `amd64` `i386` `arm64` `armhf` `ppc64el` `s390x`.
|
||||
:::
|
||||
|
||||
`snap` installs Gaia binaries as `gaia.gaiad` and `gaia.gaiacli`. It is recommended to create commands aliases for the user's convenience once the package is installed:
|
||||
|
||||
```
|
||||
$ sudo snap alias gaia.gaiad gaiad
|
||||
$ sudo snap alias gaia.gaiacli gaiacli
|
||||
```
|
||||
|
||||
::: warning
|
||||
Note that the binaries provided by the snap package save their data into **$HOME/snap/gaia/** instead of **$HOME**.
|
||||
:::
|
||||
|
||||
Please refer to [Snap documentation](https://docs.snapcraft.io/installing-snapd/6735) for specific information on how to install `snap` on your distribution.
|
||||
**Do not use snap at this time to install the binaries for production until we have a reproduceable binary system.**
|
||||
|
||||
|
||||
### Next
|
||||
|
|
|
@ -8,6 +8,6 @@ It is based on two major principles:
|
|||
|
||||
- **Composability:** Anyone can create a module for the Cosmos-SDK, and integrating the already-built modules is as simple as importing them into your blockchain application.
|
||||
|
||||
- **Capabilities:** The SDK is inspired by capabilities-based security, and informed by years of wrestling with blockchain state-machines. 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-cababilities. 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. For example, if an instance of module A's keepers is passed to module B, the latter will be able to call a restricted set of module A's functions. The capabilities of each keeper are defined by the module's developer, and it's the developer's job to understand and audit the safety of foreign code from 3rd party modules based on the capabilities they are passing into each third party module. For a deeper look at capabilities, jump to [this section](./ocap.md).
|
||||
- **Capabilities:** The SDK is inspired by capabilities-based security, and informed by years of wrestling with blockchain state-machines. 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. 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. For example, if an instance of module A's keepers is passed to module B, the latter will be able to call a restricted set of module A's functions. The capabilities of each keeper are defined by the module's developer, and it's the developer's job to understand and audit the safety of foreign code from 3rd party modules based on the capabilities they are passing into each third party module. For a deeper look at capabilities, jump to [this section](./ocap.md).
|
||||
|
||||
### Next, learn more about the [SDK Application Architecture](./sdk-app-architecture.md)
|
||||
### Next, learn more about the [SDK Application Architecture](./sdk-app-architecture.md)
|
||||
|
|
|
@ -32,7 +32,7 @@ The Cosmos SDK gives you maximum flexibility to define the state of your applica
|
|||
|
||||
## Tendermint
|
||||
|
||||
As a developer, you just have to define the state machine using the Cosmos-SDK, and [*Tendermint*](https://tendermint.com/docs/introduction/introduction.html) will handle replication over the network for you.
|
||||
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.
|
||||
|
||||
|
||||
```
|
||||
|
@ -52,7 +52,7 @@ 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 reponsible 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/introduction.html).
|
||||
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 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).
|
||||
|
||||
|
@ -81,7 +81,7 @@ Tendermint passes transactions from the network to the application through an in
|
|||
+---------------------+
|
||||
```
|
||||
|
||||
Note that Tendermint only handles transaction bytes. It has no knowledge of what these bytes realy mean. All Tendermint does is to order them deterministically. It is the job of the application to give meaning to these bytes. Tendermint passes the bytes to the application via the ABCI, and expects a return code to inform it if the message was succesful or not.
|
||||
Note that Tendermint only handles transaction bytes. It has no knowledge of what these bytes really mean. All Tendermint does is to order them deterministically. It is the job of the application to give meaning to these bytes. Tendermint passes the bytes to the application via the ABCI, and expects a return code to inform it if the message was successful or not.
|
||||
|
||||
Here are the most important messages of the ABCI:
|
||||
|
||||
|
|
|
@ -74,9 +74,9 @@ The power of the Cosmos SDK lies in its modularity. SDK applications are built b
|
|||
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 in `baseapp`'s methods). 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-cababilities](./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 in `baseapp`'s methods). 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](./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:
|
||||
SDK modules are defined in the `x/` folder of the SDK. Some core modules include:
|
||||
|
||||
- `x/auth`: Used to manage accounts and signatures.
|
||||
- `x/bank`: Used to enable tokens and token transfers.
|
||||
|
|
|
@ -0,0 +1,519 @@
|
|||
# 委托人指南 (CLI)
|
||||
|
||||
|
||||
本文介绍了如何使用Cosmos Hub的命令行交互(CLI)程序实现通证委托的相关知识和操作步骤。
|
||||
|
||||
同时,本文也介绍了如何管理账户,如何从筹款人那里恢复账户,以及如何使用一个硬件钱包的相关知识。
|
||||
|
||||
::: 风险提示
|
||||
|
||||
**重要提示**:请务必按照下面的操作步骤谨慎操作,过程中发生任何错误都有可能导致您永远失去所拥有的通证。因此,请在开始操作之前先仔细阅读全文,如果有任何问题可以联系我们获得支持。
|
||||
|
||||
|
||||
另请注意,您即将要与Cosmos Hub进行交互,Cosmos Hub仍然是一个试验型的区块链技术软件。虽然Cosmos Hub区块链是应用现有最新技术开发并经过审核的,但我们仍然可能会在运行时遇到问题,需要不断更新和修复漏洞。此外,使用区块链技术仍然要求有很高的技术能力,并且有可能遇到我们无法预知和控制的风险。使用Cosmos Hub前,您需要充分了解与加密软件相关的潜在风险(请参考[Cosmos跨链贡献条款](https://github.com/cosmos/cosmos/blob/master/fundraiser/Interchain%20Cosmos%20Contribution%20Terms%20-%20FINAL.pdf)中关于风险的部分条款),并且我们跨链基金会和(或)Tendermint团队对于因为使用本产品而可能产生的损失不承担任何责任。使用Cosmos Hub需要遵守Apache 2.0开源软件授权条款,用户需要自己承担所有责任,所使用的软件按“现状”提供且不提供任何形式的保障或条件。
|
||||
:::
|
||||
|
||||
|
||||
请务必谨慎行事!
|
||||
|
||||
## 目录
|
||||
|
||||
- [安装 `gaiacli`](#安装-gaiacli)
|
||||
- [Cosmos账户](#Cosmos账户)
|
||||
+ [通过募资人恢复一个账户](#通过募资人恢复一个账户)
|
||||
+ [创建一个账户](#创建一个账户)
|
||||
- [访问Cosmos Hub网络](#访问Cosmos-Hub网络)
|
||||
+ [运行您自己的全节点](#运行您自己的全节点)
|
||||
+ [连接到一个远程全节点](#连接到一个远程全节点)
|
||||
- [设置`gaiacli`](#设置-gaiacli)
|
||||
- [状态查询](#状态查询)
|
||||
- [发起交易](#发起交易)
|
||||
+ [关于gas费和手续费](#关于gas费和手续费)
|
||||
+ [抵押Atom通证 & 提取奖励](#抵押atom通证--提取奖励)
|
||||
+ [参与链上治理](#参与链上治理)
|
||||
+ [从一台离线电脑上签署交易](#从一台离线电脑上签署交易)
|
||||
|
||||
## 安装 `gaiacli`
|
||||
|
||||
`gaiacli`: 与`gaiad`全节点交互的命令行用户界面。
|
||||
|
||||
::: 安全提示
|
||||
|
||||
**请检查并且确认你下载的`gaiacli`是可获得的最新稳定版本**
|
||||
:::
|
||||
|
||||
|
||||
[**下载已编译代码**]暂不提供
|
||||
|
||||
|
||||
[**通过源代码安装**](https://cosmos.network/docs/gaia/installation.html)
|
||||
|
||||
::: tip 提示
|
||||
|
||||
`gaiacli` 需要通过操作系统的终端窗口使用,打开步骤如下所示:
|
||||
- **Windows**: `开始` > `所有程序` > `附件` > `终端`
|
||||
- **MacOS**: `访达` > `应用程序` > `实用工具` > `终端`
|
||||
- **Linux**: `Ctrl` + `Alt` + `T`
|
||||
:::
|
||||
|
||||
## Cosmos账户
|
||||
|
||||
每个Cosmos账户的核心基础是一个包含12或24个词的助记词组,通过这个助记词可以生成无数个Cosmos账户,例如,一组私钥/公钥对。这被称为一个硬件钱包(跟多硬件钱包相关说明请参见[BIP32](https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki))
|
||||
|
||||
```
|
||||
账户 0 账户 1 账户 2
|
||||
|
||||
+------------------+ +------------------+ +------------------+
|
||||
| | | | | |
|
||||
| 地址 0 | | 地址 1 | | 地址 2 |
|
||||
| ^ | | ^ | | ^ |
|
||||
| | | | | | | | |
|
||||
| | | | | | | | |
|
||||
| | | | | | | | |
|
||||
| + | | + | | + |
|
||||
| 公钥 0 | | 公钥 1 | | 公钥 2 |
|
||||
| ^ | | ^ | | ^ |
|
||||
| | | | | | | | |
|
||||
| | | | | | | | |
|
||||
| | | | | | | | |
|
||||
| + | | + | | + |
|
||||
| 私钥 0 | | 私钥 1 | | 私钥 2 |
|
||||
| ^ | | ^ | | ^ |
|
||||
+------------------+ +------------------+ +------------------+
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
+--------------------------------------------------------------------+
|
||||
|
|
||||
|
|
||||
+---------+---------+
|
||||
| |
|
||||
| 助记词 (Seed) |
|
||||
| |
|
||||
+-------------------+
|
||||
```
|
||||
|
||||
|
||||
私钥是控制一个账户中所存资产的钥匙。私钥是通过助记词单向产生的。如果您不小心丢失了私钥,你可以通过助记词恢复。 然而,如果你丢失了助记词,那么你就有可能失去对由这个助记词产生的所有私钥的控制。同样,如果有人获得了你的助记词,他们就可以操作所有相关账户。
|
||||
|
||||
::: 警告
|
||||
|
||||
**谨慎保管并不要告诉他人你的助记词。 为了防止资产被盗或者丢失,您最好多备份几份助记词, 并且把它们存放在只有您知道的安全地方,这样做将有助于保障您的私钥以及相关账户的安全。**
|
||||
:::
|
||||
|
||||
|
||||
Cosmos地址是一个以可读词开头的字符串(比如`cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg`) 如果有人想给你转账通证,他们就往这个地址转账。根据给定地址来推算私钥是不可行的。
|
||||
|
||||
### 通过募资人恢复一个账户
|
||||
|
||||
::: 提示
|
||||
|
||||
*注:这部分内容仅适用于众筹活动参与者*
|
||||
:::
|
||||
|
||||
|
||||
如果您是众筹的参与者,你应该有一个助记词。新产生的助记词用24个词,但是12个词的助记词组也兼容所有Cosmos工具。
|
||||
|
||||
#### 通过硬件钱包设备进行操作
|
||||
|
||||
|
||||
一个数字钱包设备的核心是通过一个助记词在多个区块链上创建账户(包括Cosmos hub)。通常,您会在初始化您的数字钱包设备时创建一个新的助记词,也可以通过已有的助记词进行导入。让我们一起来看如何将您在参与众筹时获得的助记词设定为一个数字钱包设备的seed。
|
||||
|
||||
::: 警告
|
||||
|
||||
*注意:**最好使用一个新的钱包设备**来恢复您的Cosmos账户。确实,每个数字钱包设备只能有一个助记词。 当然,您可以通过 `设置`>`设备`>`重置所有` 将一个已经有助记词的(用过的)数字钱包重新初始化。**但请注意,这样会清空您设备中现有的助记词,如果您没有做好备份的话,有可能会丢失您的资产***
|
||||
:::
|
||||
|
||||
|
||||
对于一个没有初始化的数字钱包设备,您需要做如下操作。
|
||||
|
||||
|
||||
1. 将您的数字钱包设备通过USB与电脑链接
|
||||
2. 同时按下两个按钮
|
||||
3. **不要**选择“配置一个新设备”选项,而是选择“恢复配置”
|
||||
4. 选择一个PIN
|
||||
5. 选择12个词选项
|
||||
6. 逐个按顺序输入您在众筹时获得的12个助记词
|
||||
|
||||
|
||||
现在,您的钱包已经正确地设置好您在众筹时获得的助记词,切勿丢失!任何时候您的钱包设备出现问题,您都可以通过助记词在一个新的钱包设备上恢复所有账户。
|
||||
|
||||
|
||||
接下来,请点击[这里](#使用硬件钱包设备进行操作)来学习如何生成一个账户。
|
||||
|
||||
#### 在电脑上操作
|
||||
|
||||
::: 警告
|
||||
|
||||
**注意: 在一台没有联网的计算机上执行以下操作会更加安全**
|
||||
:::
|
||||
|
||||
如果您希望通过众筹时获得的助记词恢复账户并保存相关私钥,请按以下步骤操作:
|
||||
|
||||
```bash
|
||||
gaiacli keys add <yourKeyName> --recover
|
||||
```
|
||||
|
||||
|
||||
首先,您需要输入一个密码来对您硬盘上账户`0`的私钥进行加密。每次您发出一笔交易时都将需要输入这个密码。如果您丢失了密码,您可以通过助记词来恢复您的私钥。
|
||||
|
||||
|
||||
-`<yourKeyName>` 是账户名称,用来指代用助记词生成私钥/公钥对的Cosmos账户。在您发起交易时,这个账户名称被用来识别您的账户。
|
||||
|
||||
|
||||
- 您可以通过增加 `--account` 标志来指定您账户生成的路径 (`0`, `1`, `2`, ...), `0` 是缺省值。
|
||||
|
||||
|
||||
### 创建一个账户
|
||||
|
||||
前,您需要先安装`gaiacli`,同时,您需要知道你希望在哪里保存和使用您的私钥。 最好的办法是把他们保存在一台没有上网的电脑或者一个硬件钱包设备里面。 将私钥保存在一台联网的电脑里面比较危险,任何人通过网络攻击都有可能获取您的私钥,进而盗取您的资产。
|
||||
|
||||
#### 使用硬件钱包设备进行操作
|
||||
|
||||
::: 警告
|
||||
|
||||
**建议仅使用您新买的钱包设备或者您足够信任的设备**
|
||||
:::
|
||||
|
||||
当您初始化钱包设备时,设备会产生一个24个词的助记词组。这个助记词组和Cosmos是兼容的,我们可以通过这个助记词组创建Cosmos账户。所以,您需要做的是确认您的钱包设备兼容`gaiacli`,通过下面的步骤可以帮助您确认您的设备是否兼容:
|
||||
|
||||
|
||||
1. 下载[Ledger Live应用](https://www.ledger.com/pages/ledger-live).
|
||||
2. 通过USB将钱包与计算机连接,并且将钱包固件升级到最新版本。
|
||||
3. 到Ledger Live钱包的应用商店下载”Cosmos“应用(这可能需要花些时间)。**下载”Cosmos“应用程序需要在Ledger Live钱包`Settings`选项中激活`Dev Mode`**
|
||||
4. 在你的钱包设备上操作Cosmos APP。
|
||||
|
||||
|
||||
然后,通过以下命令创建账户:
|
||||
|
||||
```bash
|
||||
gaiacli keys add <yourAccountName> --ledger
|
||||
```
|
||||
|
||||
::: 注意: 该命令仅在硬件钱包已导入并在解锁状态时才有效:::
|
||||
|
||||
|
||||
- `<yourKeyName>` 是账户名称,用来指代用助记词生成私钥/公钥对的Cosmos账户。在您发起交易时,这个账户名称被用来识别您的账户。
|
||||
|
||||
|
||||
- 您可以通过增加 `--account` 标志来指定您账户生成的路径 (`0`, `1`, `2`, ...), `0` 是缺省值。
|
||||
|
||||
#### 使用电脑设备进行操作
|
||||
|
||||
::: 警告
|
||||
|
||||
**注意:在一台没有联网的电脑上操作会更加安全**
|
||||
:::
|
||||
|
||||
然后,通过以下命令创建账户:
|
||||
|
||||
```bash
|
||||
gaiacli keys add <yourKeyName>
|
||||
```
|
||||
|
||||
这个命令会产生一个24个词的助记词组,并且同时保存账户 `0` 的私钥和公钥。 另外,您还需要输入一个密码来对您硬盘上账户`0`的私钥进行加密。 每次您发出一笔交易时都将需要输入这个密码。如果您丢失了密码,您可以通过助记词来恢复您的私钥。
|
||||
|
||||
::: 危险提示
|
||||
|
||||
**千万不要丢失或者告诉其他人你的12个词的助记词组。 为了防止资产被盗或者丢失,您最好多备份几份助记词, 并且把它们存放在只有您知道的安全地方,如果有人取得您的助记词,那么他也就取得了您的私钥并且可以控制相关账户。**
|
||||
:::
|
||||
|
||||
::: 警告
|
||||
在确认已经安全保存好您的助记词以后(至少3遍!),你可以用如下命令清除终端窗口中的命令历史记录,以防有人通过历史记录获得您的助记词。
|
||||
|
||||
```bash
|
||||
history -c
|
||||
rm ~/.bash_history
|
||||
```
|
||||
:::
|
||||
|
||||
你可以用以下命令使用助记词生成多个账户:
|
||||
|
||||
```bash
|
||||
gaiacli keys add <yourKeyName> --recover --account 1
|
||||
```
|
||||
|
||||
- - `<yourKeyName>` 是账户名称,用来指代用助记词生成私钥/公钥对的Cosmos账户。在您发起交易时,这个账户名称用来识别您的账户。
|
||||
|
||||
- 您可以通过增加 `--account` 标志来指定您账户生成的路径 (`0`, `1`, `2`, ...), `0` 是缺省值。
|
||||
|
||||
|
||||
这条命令需要您输入一个密码。改变账号就代表生成了一个新的账户。
|
||||
|
||||
## 访问Cosmos Hub网络
|
||||
|
||||
|
||||
为了查询网络状态和发起交易,你需要通过自建一个全节点,或者连接到其他人的全节点访问Cosmos Hub网络
|
||||
|
||||
::: 警告
|
||||
|
||||
**注意: 请不要与任何人分享您的助记词,您是唯一需要知道这些助记词的人。如果任何人通过邮件或者其他社交媒体向您要求您提供您的助记词,那就需要警惕了。 请记住,Cosmos/Tendermint团队,或跨链基金会永远不会通过邮件要求您提供您的账户密码或助记词。**
|
||||
:::
|
||||
|
||||
### 运行您自己的全节点
|
||||
|
||||
|
||||
这是最安全的途径,但需要相当多的资源。您需要有较大的带宽和至少1TB的磁盘容量来运行一个全节点。
|
||||
|
||||
|
||||
`gaia`的安装教程在[这里](https://cosmos.network/docs/gaia/installation.html), 如何运行一个全节点指导在[这里](https://cosmos.network/docs/gaia/join-testnet.html)
|
||||
|
||||
### 连接到一个远程全节点
|
||||
|
||||
|
||||
如果您不想或没有能力运行一个全节点,您也可以连接到其他人的全节点。您需要谨慎的选择一个可信的运营商,因为恶意的运营商往往会向您反馈错误的查询结果,或者对您的交易进行监控。 然而,他们永远也无法盗取您的资产,因为您的私钥仅保持在您的本地计算机或者钱包设备中。 验证人,钱包供应商或者交易所是可以提供全节点的运营商。
|
||||
|
||||
|
||||
连接到其他人提供的全节点,你需要一个全节点地址,如`https://77.87.106.33:26657`。这个地址是您的供应商提供的一个可信的接入地址。你会在下一节中用到这个地址。
|
||||
|
||||
## 设置 `gaiacli`
|
||||
|
||||
::: 提示
|
||||
|
||||
**在开始设置 `gaiacli`前,请确认你已经可以[访问Cosmos Hub网络](#访问cosmos-hub网络)**
|
||||
:::
|
||||
|
||||
::: 警告
|
||||
|
||||
**请确认您使用的`gaiacli`是最新的稳定版本**
|
||||
:::
|
||||
|
||||
无论您是否在自己运行一个节点,`gaiacli` 都可以帮您实现与Cosmos Hub网络的交互。让我们来完成对它的配置。
|
||||
|
||||
|
||||
您需要用下面的命令行完成对`gaiacli`的配置:
|
||||
|
||||
```bash
|
||||
gaiacli config <flag> <value>
|
||||
```
|
||||
|
||||
|
||||
此命名允许您为每个参数设置缺省值。
|
||||
|
||||
|
||||
首先,设置你想要访问的全节点的地址:
|
||||
|
||||
```bash
|
||||
gaiacli config node <host>:<port
|
||||
|
||||
// 样例: gaiacli config node https://77.87.106.33:26657
|
||||
```
|
||||
|
||||
|
||||
如果你是自己运行全节点,可以使用 `tcp://localhost:26657` 作为地址。
|
||||
|
||||
|
||||
然后,让我们设置 `--trust-node` 指标的缺省值。
|
||||
|
||||
```bash
|
||||
gaiacli config trust-node false
|
||||
|
||||
// Set to true if you run a light-client node, false otherwise
|
||||
```
|
||||
|
||||
最后,让我们设置需要访问区块链的 `chain-id`
|
||||
|
||||
```bash
|
||||
gaiacli config chain-id gos-6
|
||||
```
|
||||
|
||||
## 状态查询
|
||||
|
||||
::: 提示
|
||||
** 准备抵押ATOM通证和取回奖励前,需要先完成 [`gaiacli` 配置](#设置-gaiacli)**
|
||||
:::
|
||||
|
||||
|
||||
`gaiacli` 可以帮助您获得所有区块链的相关信息, 比如账户余额,抵押通证数量,奖励,治理提案以及其他信息。下面是一组用于委托操作的命令
|
||||
|
||||
```bash
|
||||
|
||||
// 查询账户余额或者其他账户相关信息
|
||||
gaiacli query account
|
||||
|
||||
|
||||
// 查询验证人列表
|
||||
gaiacli query staking validators
|
||||
|
||||
|
||||
// 查询指定地址的验证人的信息(e.g. cosmosvaloper1n5pepvmgsfd3p2tqqgvt505jvymmstf6s9gw27)
|
||||
gaiacli query staking validator <validatorAddress>
|
||||
|
||||
|
||||
//查询指定地址的验证人相关的所有委托信息 (e.g. cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg)
|
||||
gaiacli query staking delegations <delegatorAddress>
|
||||
|
||||
// 查询从一个指定地址的委托人(e.g. cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg)和一个指定地址的验证人(e.g. cosmosvaloper1n5pepvmgsfd3p2tqqgvt505jvymmstf6s9gw27) 之间的委托交易
|
||||
gaiacli query staking delegation <delegatorAddress> <validatorAddress>
|
||||
|
||||
// 查询一个指定地址的委托人(e.g. cosmos10snjt8dmpr5my0h76xj48ty80uzwhraqalu4eg)所能获得的奖励情况
|
||||
gaiacli query distr rewards <delegatorAddress>
|
||||
|
||||
// 查询所有现在正等待抵押的提案
|
||||
gaiacli query gov proposals --status deposit_period
|
||||
|
||||
//查询所有现在正等待投票的填
|
||||
gaiacli query gov proposals --status voting_period
|
||||
|
||||
// 查询一个指定propsalID的提案信息
|
||||
gaiacli query gov proposal <proposalID>
|
||||
```
|
||||
|
||||
需要了解跟多的命令,只需要用:
|
||||
|
||||
```bash
|
||||
gaiacli query
|
||||
```
|
||||
|
||||
对于每条命令,您都可以使用`-h` 或 `--help` 参数来获得更多的信息。
|
||||
|
||||
## 发起交易
|
||||
|
||||
### 关于gas费和手续费
|
||||
|
||||
|
||||
Cosmos Hub网络上的交易在被执行时需要支付手续费。这个手续费是用于支付执行交易所需的gas。计算公式如下:
|
||||
```
|
||||
fees = gas * gasPrices
|
||||
```
|
||||
|
||||
`gas` 的多少取决于交易类型,不同的交易类型会收取不同的 `gas` 。每个交易的 `gas` 费是在实际执行过程中计算的,但我们可以通过设置 `gas` 参数中的 `auto` 值实现在交易前对 `gas` 费的估算,但这只是一个粗略的估计,你可以通过 `--gas-adjustment` (缺省值 `1.0`) 对预估的`gas` 值进行调节,以确保为交易支付足够的`gas` 。
|
||||
|
||||
`gasPrice` 用于设置单位 `gas` 的价格。每个验证人会设置一个最低gas价`min-gas-price`, 并只会将`gasPrice`大于`min-gas-price`的交易打包。
|
||||
|
||||
交易的`fees` 是`gas` 和 `gasPrice`的乘积。作为一个用户,你需要输入3个参数中至少2个, `gasPrice`/`fees`的值越大,您的交易就越有机会被打包执行。
|
||||
|
||||
### 抵押Atom通证 & 提取奖励
|
||||
|
||||
::: 提示
|
||||
**在您抵押通证或取回奖励之前,您需要完成[`gaiacli` 设置](#设置-gaiacli) 和 [创建账户](#创建一个账户)**
|
||||
:::
|
||||
|
||||
::: 警告
|
||||
**在抵押通证前,请仔细阅读[委托者常见问题](https://cosmos.network/resources/delegators) 并且理解其中的风险和责任**
|
||||
:::
|
||||
|
||||
::: 警告
|
||||
**注意:执行以下命令需要在一台联网的计算机。用一个硬件钱包设备执行这些命令会更安全。关于离线交易过程请看[这里](#从一台离线电脑上签署交易).**
|
||||
:::
|
||||
|
||||
```bash
|
||||
// 向指定验证人绑定一定数量的Atom通证
|
||||
// 参数设定样例: <validatorAddress>=cosmosvaloper18thamkhnj9wz8pa4nhnp9rldprgant57pk2m8s, <amountToBound>=10000stake, <gasPrice>=0.001stake
|
||||
|
||||
gaiacli tx staking delegate <validatorAddress> <amountToBond> --from <delegatorKeyName> --gas auto --gas-prices <gasPrice>
|
||||
|
||||
|
||||
// 提取所有的奖励
|
||||
// 参数设定样例: <gasPrice>=0.001stake
|
||||
|
||||
gaiacli tx distr withdraw-all-rewards --from <delegatorKeyName> --gas auto --gas-prices <gasPrice>
|
||||
|
||||
|
||||
// 向指定验证人申请解绑一定数量的Atom通证
|
||||
// 解绑的通证需要3周后才能完全解绑并可以交易,
|
||||
// 参数设定样例: <validatorAddress>=cosmosvaloper18thamkhnj9wz8pa4nhnp9rldprgant57pk2m8s, <amountToUnbound>=10000stake, <gasPrice>=0.001stake
|
||||
|
||||
gaiacli tx staking unbond <validatorAddress> <amountToUnbond> --from <delegatorKeyName> --gas auto --gas-prices <gasPrice>
|
||||
```
|
||||
|
||||
::: 提示
|
||||
:::
|
||||
如果您是使用一个联网的钱包设备,在交易被广播到网络前您需要在设备上确认交易。
|
||||
|
||||
确认您的交易已经发出,可以用以下查询:
|
||||
|
||||
```bash
|
||||
// 您的账户余额在您抵押Atom通证或者取回奖励后会发生变化
|
||||
gaiacli query account
|
||||
|
||||
// 您在抵押后应该能查到委托交易
|
||||
gaiacli query staking delegations <delegatorAddress>
|
||||
|
||||
// 如果交易已经被打包,将会返回交易记录(tx)
|
||||
// 在以下查询命令中可以使用显示的交易哈希值作为参数
|
||||
gaiacli query tx <txHash>
|
||||
|
||||
```
|
||||
|
||||
如果您是连接到一个可信全节点的话,您可以通过一个区块链浏览器做检查。
|
||||
|
||||
## 参与链上治理
|
||||
|
||||
#### 链上治理入门
|
||||
|
||||
Cosmos Hub有一个内建的治理系统,该系统允许抵押通证的持有人参与提案投票。系统现在支持3种提案类型:
|
||||
|
||||
- `Text Proposals`: 这是最基本的一种提案类型,通常用于获得大家对某个网络治理意见的观点。
|
||||
- `Parameter Proposals`: 这种提案通常用于改变网络参数的设定。
|
||||
- `Software Upgrade Proposal`: 这个提案用于升级Hub的软件。
|
||||
|
||||
任何Atom通证的持有人都能够提交一个提案。为了让一个提案获准公开投票,提议人必须要抵押一定量的通证 `deposit`,且抵押值必须大于 `minDeposit` 参数设定值. 提案的抵押不需要提案人一次全部交付。如果早期提案人交付的 `deposit` 不足,那么提案进入 `deposit_period` 状态。 此后,任何通证持有人可以通过 `depositTx` 交易增加对提案的抵押。
|
||||
|
||||
当`deposit` 达到 `minDeposit`,提案进入2周的 `voting_period` 。 任何**抵押了通证**的持有人都可以参与对这个提案的投票。投票的选项有`Yes`, `No`, `NoWithVeto` 和 `Abstain`。投票的权重取决于投票人所抵押的通证数量。如果通证持有人不投票,那么委托人将继承其委托的验证人的投票选项。当然,委托人也可以自己投出与所委托验证人不同的票。
|
||||
|
||||
|
||||
当投票期结束后,获得50%(不包括投`Abstain `票)以上 `Yes` 投票权重且少于33.33% 的`NoWithVeto`(不包括投`Abstain `票)提案将被接受,
|
||||
|
||||
#### 实践练习
|
||||
|
||||
::: 提示
|
||||
**在您能够抵押通证或者提取奖励以前,您需要了解[通证抵押](#抵押atom通证--提取奖励)**
|
||||
:::
|
||||
|
||||
::: 警告
|
||||
|
||||
**注意:执行以下命令需要一台联网的计算机。用一个硬件钱包设备执行这些命令会更安全。关于离线交易过程请看[这里](#从一台离线电脑上签署交易).**
|
||||
:::
|
||||
|
||||
```bash
|
||||
// 提交一个提案
|
||||
// <type>=text/parameter_change/software_upgrade
|
||||
// ex value for flag: <gasPrice>=0.0001stake
|
||||
|
||||
gaiacli tx gov submit-proposal --title "Test Proposal" --description "My awesome proposal" --type <type> --deposit=10stake --gas auto --gas-prices <gasPrice> --from <delegatorKeyName>
|
||||
|
||||
// 增加对提案的抵押
|
||||
// Retrieve proposalID from $gaiacli query gov proposals --status deposit_period
|
||||
// 通过 $gaiacli query gov proposals --status deposit_period 命令获得 `proposalID`
|
||||
// 参数设定样例: <deposit>=1stake
|
||||
|
||||
gaiacli tx gov deposit <proposalID> <deposit> --gas auto --gas-prices <gasPrice> --from <delegatorKeyName>
|
||||
|
||||
// 对一个提案投票
|
||||
// Retrieve proposalID from $gaiacli query gov proposals --status voting_period
|
||||
通过 $gaiacli query gov proposals --status deposit_period 命令获得 `proposalID`
|
||||
// <option>=yes/no/no_with_veto/abstain
|
||||
|
||||
gaiacli tx gov vote <proposalID> <option> --gas auto --gas-prices <gasPrice> --from <delegatorKeyName>
|
||||
```
|
||||
|
||||
### 从一台离线电脑上签署交易
|
||||
|
||||
|
||||
如果你没有数字钱包设备,而且希望和一台存有私钥的没有联网的电脑进行交互,你可以使用如下过程。首先,在**联网的电脑上**生成一个没有签名的交易,然后通过下列命令操作(下面以抵押交易为例):
|
||||
|
||||
```bash
|
||||
// 抵押Atom通证
|
||||
// 参数设定样例: <amountToBound>=10000stake, <bech32AddressOfValidator>=cosmosvaloper18thamkhnj9wz8pa4nhnp9rldprgant57pk2m8s, <gasPrice>=0.001stake
|
||||
|
||||
gaiacli tx staking delegate <validatorAddress> <amountToBond> --from <delegatorKeyName> --gas auto --gas-prices <gasPrice> --generate-only > unsignedTX.json
|
||||
```
|
||||
|
||||
然后,复制 `unsignedTx.json` 并且帮它转移到没有联网的电脑上(比如通过U盘)。如果没有在没联网的电脑上建立账户,可先[在没有联网的电脑上建立账户](#使用电脑设备进行操作)。为了进一步保障安全,你可以在签署交易前用以下命令对参数进行检查。
|
||||
|
||||
```bash
|
||||
cat unsignedTx.json
|
||||
```
|
||||
|
||||
现在,通过以下命令对交易签名:
|
||||
|
||||
```bash
|
||||
gaiacli tx sign unsignedTx.json --from-addr <delegatorAddr>> signedTx.json
|
||||
```
|
||||
|
||||
复制 `signedTx.json` 并转移回联网的那台电脑。最后,用以下命令向网络广播交易。
|
||||
|
||||
```bash
|
||||
gaiacli tx broadcast signedTx.json
|
||||
```
|
|
@ -179,7 +179,9 @@ func (coins DecCoins) TruncateDecimal() (Coins, DecCoins) {
|
|||
for i, coin := range coins {
|
||||
truncated, change := coin.TruncateDecimal()
|
||||
out[i] = truncated
|
||||
changeSum = changeSum.Add(DecCoins{change})
|
||||
if !change.IsZero() {
|
||||
changeSum = changeSum.Add(DecCoins{change})
|
||||
}
|
||||
}
|
||||
|
||||
return out, changeSum
|
||||
|
|
|
@ -123,7 +123,8 @@ func TestSendNotEnoughBalance(t *testing.T) {
|
|||
origSeq := res1.GetSequence()
|
||||
|
||||
sendMsg := NewMsgSend(addr1, addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)})
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{sendMsg}, []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1)
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{sendMsg}, []uint64{origAccNum}, []uint64{origSeq}, false, false, priv1)
|
||||
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)})
|
||||
|
||||
|
@ -173,7 +174,8 @@ func TestMsgMultiSendWithAccounts(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
|
||||
for _, eb := range tc.expectedBalances {
|
||||
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
|
||||
|
@ -212,7 +214,8 @@ func TestMsgMultiSendMultipleOut(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
|
||||
for _, eb := range tc.expectedBalances {
|
||||
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
|
||||
|
@ -241,7 +244,7 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) {
|
|||
testCases := []appTestCase{
|
||||
{
|
||||
msgs: []sdk.Msg{multiSendMsg3},
|
||||
accNums: []uint64{0, 0},
|
||||
accNums: []uint64{0, 2},
|
||||
accSeqs: []uint64{0, 0},
|
||||
expSimPass: true,
|
||||
expPass: true,
|
||||
|
@ -256,7 +259,8 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
|
||||
for _, eb := range tc.expectedBalances {
|
||||
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
|
||||
|
@ -289,7 +293,7 @@ func TestMsgMultiSendDependent(t *testing.T) {
|
|||
},
|
||||
{
|
||||
msgs: []sdk.Msg{multiSendMsg4},
|
||||
accNums: []uint64{0},
|
||||
accNums: []uint64{1},
|
||||
accSeqs: []uint64{0},
|
||||
expSimPass: true,
|
||||
expPass: true,
|
||||
|
@ -301,7 +305,8 @@ func TestMsgMultiSendDependent(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
|
||||
|
||||
for _, eb := range tc.expectedBalances {
|
||||
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
|
||||
|
|
|
@ -79,9 +79,7 @@ func (k Keeper) WithdrawValidatorCommission(ctx sdk.Context, valAddr sdk.ValAddr
|
|||
}
|
||||
|
||||
coins, remainder := commission.TruncateDecimal()
|
||||
|
||||
// leave remainder to withdraw later
|
||||
k.SetValidatorAccumulatedCommission(ctx, valAddr, remainder)
|
||||
k.SetValidatorAccumulatedCommission(ctx, valAddr, remainder) // leave remainder to withdraw later
|
||||
|
||||
// update outstanding
|
||||
outstanding := k.GetValidatorOutstandingRewards(ctx, valAddr)
|
||||
|
|
|
@ -237,9 +237,16 @@ func (k Keeper) GetValidatorAccumulatedCommission(ctx sdk.Context, val sdk.ValAd
|
|||
|
||||
// set accumulated commission for a validator
|
||||
func (k Keeper) SetValidatorAccumulatedCommission(ctx sdk.Context, val sdk.ValAddress, commission types.ValidatorAccumulatedCommission) {
|
||||
var bz []byte
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := k.cdc.MustMarshalBinaryLengthPrefixed(commission)
|
||||
store.Set(GetValidatorAccumulatedCommissionKey(val), b)
|
||||
if commission.IsZero() {
|
||||
bz = k.cdc.MustMarshalBinaryLengthPrefixed(types.InitialValidatorAccumulatedCommission())
|
||||
} else {
|
||||
bz = k.cdc.MustMarshalBinaryLengthPrefixed(commission)
|
||||
}
|
||||
|
||||
store.Set(GetValidatorAccumulatedCommissionKey(val), bz)
|
||||
}
|
||||
|
||||
// delete accumulated commission for a validator
|
||||
|
|
|
@ -13,7 +13,10 @@ import (
|
|||
|
||||
func TestTickExpiredDepositPeriod(t *testing.T) {
|
||||
mapp, keeper, _, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
keeper.ck.SetSendEnabled(ctx, true)
|
||||
govHandler := NewHandler(keeper)
|
||||
|
@ -56,7 +59,10 @@ func TestTickExpiredDepositPeriod(t *testing.T) {
|
|||
|
||||
func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
|
||||
mapp, keeper, _, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
keeper.ck.SetSendEnabled(ctx, true)
|
||||
govHandler := NewHandler(keeper)
|
||||
|
@ -113,7 +119,10 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
|
|||
|
||||
func TestTickPassedDepositPeriod(t *testing.T) {
|
||||
mapp, keeper, _, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
keeper.ck.SetSendEnabled(ctx, true)
|
||||
govHandler := NewHandler(keeper)
|
||||
|
@ -156,7 +165,10 @@ func TestTickPassedDepositPeriod(t *testing.T) {
|
|||
func TestTickPassedVotingPeriod(t *testing.T) {
|
||||
mapp, keeper, _, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
SortAddresses(addrs)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
keeper.ck.SetSendEnabled(ctx, true)
|
||||
govHandler := NewHandler(keeper)
|
||||
|
|
|
@ -27,7 +27,10 @@ func TestEqualProposals(t *testing.T) {
|
|||
// Generate mock app and keepers
|
||||
mapp, keeper, _, addrs, _, _ := getMockApp(t, 2, GenesisState{}, nil)
|
||||
SortAddresses(addrs)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
|
||||
// Create two proposals
|
||||
|
@ -56,11 +59,13 @@ func TestEqualProposals(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestImportExportQueues(t *testing.T) {
|
||||
|
||||
// Generate mock app and keepers
|
||||
mapp, keeper, _, addrs, _, _ := getMockApp(t, 2, GenesisState{}, nil)
|
||||
SortAddresses(addrs)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
|
||||
// Create two proposals, put the second into the voting period
|
||||
|
@ -82,7 +87,9 @@ func TestImportExportQueues(t *testing.T) {
|
|||
genState := ExportGenesis(ctx, keeper)
|
||||
mapp2, keeper2, _, _, _, _ := getMockApp(t, 2, genState, genAccs)
|
||||
|
||||
mapp2.BeginBlock(abci.RequestBeginBlock{})
|
||||
header = abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp2.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx2 := mapp2.BaseApp.NewContext(false, abci.Header{})
|
||||
|
||||
// Jump the time forward past the DepositPeriod and VotingPeriod
|
||||
|
|
|
@ -13,7 +13,10 @@ import (
|
|||
|
||||
func TestGetSetProposal(t *testing.T) {
|
||||
mapp, keeper, _, _, _, _ := getMockApp(t, 0, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
|
@ -26,7 +29,10 @@ func TestGetSetProposal(t *testing.T) {
|
|||
|
||||
func TestIncrementProposalNumber(t *testing.T) {
|
||||
mapp, keeper, _, _, _, _ := getMockApp(t, 0, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
|
||||
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
|
@ -41,9 +47,11 @@ func TestIncrementProposalNumber(t *testing.T) {
|
|||
|
||||
func TestActivateVotingPeriod(t *testing.T) {
|
||||
mapp, keeper, _, _, _, _ := getMockApp(t, 0, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
|
||||
require.True(t, proposal.GetVotingStartTime().Equal(time.Time{}))
|
||||
|
@ -63,9 +71,11 @@ func TestActivateVotingPeriod(t *testing.T) {
|
|||
func TestDeposits(t *testing.T) {
|
||||
mapp, keeper, _, addrs, _, _ := getMockApp(t, 2, GenesisState{}, nil)
|
||||
SortAddresses(addrs)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
|
||||
|
@ -149,9 +159,11 @@ func TestDeposits(t *testing.T) {
|
|||
func TestVotes(t *testing.T) {
|
||||
mapp, keeper, _, addrs, _, _ := getMockApp(t, 2, GenesisState{}, nil)
|
||||
SortAddresses(addrs)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||
proposalID := proposal.GetProposalID()
|
||||
|
||||
|
@ -204,7 +216,10 @@ func TestVotes(t *testing.T) {
|
|||
|
||||
func TestProposalQueues(t *testing.T) {
|
||||
mapp, keeper, _, _, _, _ := getMockApp(t, 0, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
mapp.InitChainer(ctx, abci.RequestInitChain{})
|
||||
|
||||
|
|
|
@ -38,7 +38,10 @@ func createValidators(t *testing.T, stakingHandler sdk.Handler, ctx sdk.Context,
|
|||
|
||||
func TestTallyNoOneVotes(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -63,7 +66,10 @@ func TestTallyNoOneVotes(t *testing.T) {
|
|||
|
||||
func TestTallyNoQuorum(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -89,7 +95,10 @@ func TestTallyNoQuorum(t *testing.T) {
|
|||
|
||||
func TestTallyOnlyValidatorsAllYes(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -119,7 +128,10 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) {
|
|||
|
||||
func TestTallyOnlyValidators51No(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -148,7 +160,10 @@ func TestTallyOnlyValidators51No(t *testing.T) {
|
|||
|
||||
func TestTallyOnlyValidators51Yes(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -180,7 +195,10 @@ func TestTallyOnlyValidators51Yes(t *testing.T) {
|
|||
|
||||
func TestTallyOnlyValidatorsVetoed(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -212,7 +230,10 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) {
|
|||
|
||||
func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -244,7 +265,10 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) {
|
|||
|
||||
func TestTallyOnlyValidatorsAbstainFails(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -276,7 +300,10 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) {
|
|||
|
||||
func TestTallyOnlyValidatorsNonVoter(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -306,7 +333,10 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) {
|
|||
|
||||
func TestTallyDelgatorOverride(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -344,7 +374,10 @@ func TestTallyDelgatorOverride(t *testing.T) {
|
|||
|
||||
func TestTallyDelgatorInherit(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -380,7 +413,10 @@ func TestTallyDelgatorInherit(t *testing.T) {
|
|||
|
||||
func TestTallyDelgatorMultipleOverride(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -420,7 +456,10 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) {
|
|||
|
||||
func TestTallyDelgatorMultipleInherit(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
@ -471,7 +510,10 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) {
|
|||
|
||||
func TestTallyJailedValidator(t *testing.T) {
|
||||
mapp, keeper, sk, addrs, _, _ := getMockApp(t, 10, GenesisState{}, nil)
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
|
||||
stakingHandler := staking.NewHandler(sk)
|
||||
|
||||
|
|
|
@ -72,10 +72,17 @@ func TestIBCMsgs(t *testing.T) {
|
|||
Sequence: 0,
|
||||
}
|
||||
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{transferMsg}, []uint64{0}, []uint64{0}, true, true, priv1)
|
||||
header := abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{transferMsg}, []uint64{0}, []uint64{0}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, emptyCoins)
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{transferMsg}, []uint64{0}, []uint64{1}, false, false, priv1)
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{receiveMsg}, []uint64{0}, []uint64{2}, true, true, priv1)
|
||||
|
||||
header = abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{transferMsg}, []uint64{0}, []uint64{1}, false, false, priv1)
|
||||
|
||||
header = abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{receiveMsg}, []uint64{0}, []uint64{2}, true, true, priv1)
|
||||
mock.CheckBalance(t, mapp, addr1, coins)
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{receiveMsg}, []uint64{0}, []uint64{2}, false, false, priv1)
|
||||
|
||||
header = abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, header, []sdk.Msg{receiveMsg}, []uint64{0}, []uint64{2}, false, false, priv1)
|
||||
}
|
||||
|
|
|
@ -60,15 +60,17 @@ func TestCheckAndDeliverGenTx(t *testing.T) {
|
|||
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, []sdk.Msg{msg},
|
||||
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}
|
||||
res := SignCheckDeliver(
|
||||
t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{msg},
|
||||
t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{msg},
|
||||
[]uint64{accs[1].GetAccountNumber()}, []uint64{accs[1].GetSequence() + 1},
|
||||
true, false, privKeys[1],
|
||||
)
|
||||
|
@ -77,8 +79,9 @@ func TestCheckAndDeliverGenTx(t *testing.T) {
|
|||
require.Equal(t, sdk.CodespaceRoot, res.Codespace)
|
||||
|
||||
// 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, []sdk.Msg{msg},
|
||||
t, mApp.Cdc, mApp.BaseApp, header, []sdk.Msg{msg},
|
||||
[]uint64{accs[0].GetAccountNumber()}, []uint64{accs[0].GetSequence() + 1},
|
||||
true, true, privKeys[0],
|
||||
)
|
||||
|
|
|
@ -72,9 +72,10 @@ func CheckGenTx(
|
|||
// 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,
|
||||
msgs []sdk.Msg, accNums, seq []uint64, expSimPass, expPass bool,
|
||||
priv ...crypto.PrivKey) sdk.Result {
|
||||
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 {
|
||||
|
||||
tx := GenTx(msgs, accNums, seq, priv...)
|
||||
|
||||
|
@ -91,7 +92,7 @@ func SignCheckDeliver(t *testing.T, cdc *codec.Codec, app *baseapp.BaseApp,
|
|||
}
|
||||
|
||||
// Simulate a sending a transaction and committing a block
|
||||
app.BeginBlock(abci.RequestBeginBlock{})
|
||||
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
res = app.Deliver(tx)
|
||||
|
||||
if expPass {
|
||||
|
|
|
@ -111,9 +111,13 @@ func TestSlashingMsgs(t *testing.T) {
|
|||
createValidatorMsg := staking.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description, commission, sdk.OneInt(),
|
||||
)
|
||||
mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1)
|
||||
|
||||
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)})
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header = abci.Header{Height: mapp.LastBlockHeight() + 1}
|
||||
mapp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
validator := checkValidator(t, mapp, stakingKeeper, addr1, true)
|
||||
require.Equal(t, sdk.ValAddress(addr1), validator.OperatorAddress)
|
||||
|
@ -125,7 +129,8 @@ func TestSlashingMsgs(t *testing.T) {
|
|||
checkValidatorSigningInfo(t, mapp, keeper, sdk.ConsAddress(addr1), false)
|
||||
|
||||
// unjail should fail with unknown validator
|
||||
res := mock.SignCheckDeliver(t, mapp.Cdc, mapp.BaseApp, []sdk.Msg{unjailMsg}, []uint64{0}, []uint64{1}, false, false, priv1)
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -122,22 +122,28 @@ func TestStakingMsgs(t *testing.T) {
|
|||
sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description, commissionMsg, sdk.OneInt(),
|
||||
)
|
||||
|
||||
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []uint64{0}, []uint64{0}, true, true, priv1)
|
||||
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)})
|
||||
mApp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
header = abci.Header{Height: mApp.LastBlockHeight() + 1}
|
||||
mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
validator := checkValidator(t, mApp, keeper, 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()))
|
||||
|
||||
mApp.BeginBlock(abci.RequestBeginBlock{})
|
||||
header = abci.Header{Height: mApp.LastBlockHeight() + 1}
|
||||
mApp.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||
|
||||
// edit the validator
|
||||
description = NewDescription("bar_moniker", "", "", "")
|
||||
editValidatorMsg := NewMsgEditValidator(sdk.ValAddress(addr1), description, nil, nil)
|
||||
|
||||
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []uint64{0}, []uint64{1}, true, true, priv1)
|
||||
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)
|
||||
|
||||
validator = checkValidator(t, mApp, keeper, sdk.ValAddress(addr1), true)
|
||||
require.Equal(t, description, validator.Description)
|
||||
|
||||
|
@ -145,13 +151,15 @@ func TestStakingMsgs(t *testing.T) {
|
|||
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
|
||||
delegateMsg := NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin)
|
||||
|
||||
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{delegateMsg}, []uint64{0}, []uint64{0}, true, true, priv2)
|
||||
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())
|
||||
|
||||
// begin unbonding
|
||||
beginUnbondingMsg := NewMsgUndelegate(addr2, sdk.ValAddress(addr1), bondTokens.ToDec())
|
||||
mock.SignCheckDeliver(t, mApp.Cdc, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []uint64{0}, []uint64{1}, true, true, priv2)
|
||||
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)
|
||||
|
||||
// delegation should exist anymore
|
||||
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), false, sdk.Dec{})
|
||||
|
|
Loading…
Reference in New Issue