Merge branch 'develop' into rigel/minor
This commit is contained in:
commit
887251f870
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
# Build
|
# Build
|
||||||
vendor
|
vendor
|
||||||
|
.vendor-new
|
||||||
build
|
build
|
||||||
tools/bin/*
|
tools/bin/*
|
||||||
examples/build/*
|
examples/build/*
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
digest = "1:7736fc6da04620727f8f3aa2ced8d77be8e074a302820937aa5993848c769b27"
|
||||||
|
name = "github.com/ZondaX/hid-go"
|
||||||
|
packages = ["."]
|
||||||
|
pruneopts = "UT"
|
||||||
|
revision = "48b08affede2cea076a3cf13b2e3f72ed262b743"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:09a7f74eb6bb3c0f14d8926610c87f569c5cff68e978d30e9a3540aeb626fdf0"
|
digest = "1:09a7f74eb6bb3c0f14d8926610c87f569c5cff68e978d30e9a3540aeb626fdf0"
|
||||||
name = "github.com/bartekn/go-bip39"
|
name = "github.com/bartekn/go-bip39"
|
||||||
|
@ -24,14 +32,6 @@
|
||||||
revision = "4aabc24848ce5fd31929f7d1e4ea74d3709c14cd"
|
revision = "4aabc24848ce5fd31929f7d1e4ea74d3709c14cd"
|
||||||
version = "v0.1.0"
|
version = "v0.1.0"
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:70f6b224a59b2fa453debffa85c77f71063d8754b90c8c4fbad5794e2c382b0f"
|
|
||||||
name = "github.com/brejski/hid"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "06112dcfcc50a7e0e4fd06e17f9791e788fdaafc"
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:2c00f064ba355903866cbfbf3f7f4c0fe64af6638cc7d1b8bdcf3181bc67f1d8"
|
digest = "1:2c00f064ba355903866cbfbf3f7f4c0fe64af6638cc7d1b8bdcf3181bc67f1d8"
|
||||||
|
@ -498,11 +498,12 @@
|
||||||
version = "v0.9.0"
|
version = "v0.9.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:4dcb0dd65feecb068ce23a234d1a07c7868a1e39f52a6defcae0bb371d03abf6"
|
digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666"
|
||||||
name = "github.com/zondax/ledger-goclient"
|
name = "github.com/zondax/ledger-goclient"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "4296ee5701e945f9b3a7dbe51f402e0b9be57259"
|
revision = "58598458c11bc0ad1c1b8dac3dc3e11eaf270b79"
|
||||||
|
version = "v0.1.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/zondax/ledger-goclient"
|
name = "github.com/zondax/ledger-goclient"
|
||||||
revision = "4296ee5701e945f9b3a7dbe51f402e0b9be57259"
|
version = "=v0.1.0"
|
||||||
|
|
||||||
[prune]
|
[prune]
|
||||||
go-tests = true
|
go-tests = true
|
||||||
|
|
|
@ -48,6 +48,7 @@ FEATURES
|
||||||
* [lcd] Endpoints to query staking pool and params
|
* [lcd] Endpoints to query staking pool and params
|
||||||
* [lcd] [\#2110](https://github.com/cosmos/cosmos-sdk/issues/2110) Add support for `simulate=true` requests query argument to endpoints that send txs to run simulations of transactions
|
* [lcd] [\#2110](https://github.com/cosmos/cosmos-sdk/issues/2110) Add support for `simulate=true` requests query argument to endpoints that send txs to run simulations of transactions
|
||||||
* [lcd] [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add support for `generate_only=true` query argument to generate offline unsigned transactions
|
* [lcd] [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add support for `generate_only=true` query argument to generate offline unsigned transactions
|
||||||
|
* [lcd] [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) Add /sign endpoint to sign transactions generated with `generate_only=true`.
|
||||||
|
|
||||||
* Gaia CLI (`gaiacli`)
|
* Gaia CLI (`gaiacli`)
|
||||||
* [cli] Cmds to query staking pool and params
|
* [cli] Cmds to query staking pool and params
|
||||||
|
@ -57,7 +58,9 @@ FEATURES
|
||||||
* [cli] [\#2047](https://github.com/cosmos/cosmos-sdk/issues/2047) Setting the --gas flag value to 0 triggers a simulation of the tx before the actual execution. The gas estimate obtained via the simulation will be used as gas limit in the actual execution.
|
* [cli] [\#2047](https://github.com/cosmos/cosmos-sdk/issues/2047) Setting the --gas flag value to 0 triggers a simulation of the tx before the actual execution. The gas estimate obtained via the simulation will be used as gas limit in the actual execution.
|
||||||
* [cli] [\#2047](https://github.com/cosmos/cosmos-sdk/issues/2047) The --gas-adjustment flag can be used to adjust the estimate obtained via the simulation triggered by --gas=0.
|
* [cli] [\#2047](https://github.com/cosmos/cosmos-sdk/issues/2047) The --gas-adjustment flag can be used to adjust the estimate obtained via the simulation triggered by --gas=0.
|
||||||
* [cli] [\#2110](https://github.com/cosmos/cosmos-sdk/issues/2110) Add --dry-run flag to perform a simulation of a transaction without broadcasting it. The --gas flag is ignored as gas would be automatically estimated.
|
* [cli] [\#2110](https://github.com/cosmos/cosmos-sdk/issues/2110) Add --dry-run flag to perform a simulation of a transaction without broadcasting it. The --gas flag is ignored as gas would be automatically estimated.
|
||||||
* [cli] [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add --generate-only flag to build an unsigned transaction and write it to STDOUT.
|
* [cli] [\#2204](https://github.com/cosmos/cosmos-sdk/issues/2204) Support generating and broadcasting messages with multiple signatures via command line:
|
||||||
|
* [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add --generate-only flag to build an unsigned transaction and write it to STDOUT.
|
||||||
|
* [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) New `sign` command to sign transactions generated with the --generate-only flag.
|
||||||
|
|
||||||
* Gaia
|
* Gaia
|
||||||
* [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address`
|
* [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address`
|
||||||
|
|
|
@ -24,7 +24,7 @@ func BufferStdin() *bufio.Reader {
|
||||||
// It enforces the password length
|
// It enforces the password length
|
||||||
func GetPassword(prompt string, buf *bufio.Reader) (pass string, err error) {
|
func GetPassword(prompt string, buf *bufio.Reader) (pass string, err error) {
|
||||||
if inputIsTty() {
|
if inputIsTty() {
|
||||||
pass, err = speakeasy.Ask(prompt)
|
pass, err = speakeasy.FAsk(os.Stderr, prompt)
|
||||||
} else {
|
} else {
|
||||||
pass, err = readLineFromBuf(buf)
|
pass, err = readLineFromBuf(buf)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/wire"
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
@ -313,12 +314,13 @@ func TestIBCTransfer(t *testing.T) {
|
||||||
// TODO: query ibc egress packet state
|
// TODO: query ibc egress packet state
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCoinSendGenerateOnly(t *testing.T) {
|
func TestCoinSendGenerateAndSign(t *testing.T) {
|
||||||
name, password := "test", "1234567890"
|
name, password := "test", "1234567890"
|
||||||
addr, seed := CreateAddr(t, "test", password, GetKeyBase(t))
|
addr, seed := CreateAddr(t, "test", password, GetKeyBase(t))
|
||||||
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
|
cleanup, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
// create TX
|
|
||||||
|
// generate TX
|
||||||
res, body, _ := doSendWithGas(t, port, seed, name, password, addr, 0, 0, "?generate_only=true")
|
res, body, _ := doSendWithGas(t, port, seed, name, password, addr, 0, 0, "?generate_only=true")
|
||||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
var msg auth.StdTx
|
var msg auth.StdTx
|
||||||
|
@ -327,6 +329,30 @@ func TestCoinSendGenerateOnly(t *testing.T) {
|
||||||
require.Equal(t, msg.Msgs[0].Type(), "bank")
|
require.Equal(t, msg.Msgs[0].Type(), "bank")
|
||||||
require.Equal(t, msg.Msgs[0].GetSigners(), []sdk.AccAddress{addr})
|
require.Equal(t, msg.Msgs[0].GetSigners(), []sdk.AccAddress{addr})
|
||||||
require.Equal(t, 0, len(msg.Signatures))
|
require.Equal(t, 0, len(msg.Signatures))
|
||||||
|
|
||||||
|
// sign tx
|
||||||
|
var signedMsg auth.StdTx
|
||||||
|
acc := getAccount(t, port, addr)
|
||||||
|
accnum := acc.GetAccountNumber()
|
||||||
|
sequence := acc.GetSequence()
|
||||||
|
|
||||||
|
payload := authrest.SignBody{
|
||||||
|
Tx: msg,
|
||||||
|
LocalAccountName: name,
|
||||||
|
Password: password,
|
||||||
|
ChainID: viper.GetString(client.FlagChainID),
|
||||||
|
AccountNumber: accnum,
|
||||||
|
Sequence: sequence,
|
||||||
|
}
|
||||||
|
json, err := cdc.MarshalJSON(payload)
|
||||||
|
require.Nil(t, err)
|
||||||
|
res, body = Request(t, port, "POST", "/sign", json)
|
||||||
|
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||||
|
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &signedMsg))
|
||||||
|
require.Equal(t, len(msg.Msgs), len(signedMsg.Msgs))
|
||||||
|
require.Equal(t, msg.Msgs[0].Type(), signedMsg.Msgs[0].Type())
|
||||||
|
require.Equal(t, msg.Msgs[0].GetSigners(), signedMsg.Msgs[0].GetSigners())
|
||||||
|
require.Equal(t, 1, len(signedMsg.Signatures))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTxs(t *testing.T) {
|
func TestTxs(t *testing.T) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -99,6 +100,49 @@ func PrintUnsignedStdTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignStdTx appends a signature to a StdTx and returns a copy of a it. If appendSig
|
||||||
|
// is false, it replaces the signatures already attached with the new signature.
|
||||||
|
func SignStdTx(txCtx authctx.TxContext, cliCtx context.CLIContext, name string, stdTx auth.StdTx, appendSig bool) (auth.StdTx, error) {
|
||||||
|
var signedStdTx auth.StdTx
|
||||||
|
|
||||||
|
keybase, err := keys.GetKeyBase()
|
||||||
|
if err != nil {
|
||||||
|
return signedStdTx, err
|
||||||
|
}
|
||||||
|
info, err := keybase.Get(name)
|
||||||
|
if err != nil {
|
||||||
|
return signedStdTx, err
|
||||||
|
}
|
||||||
|
addr := info.GetPubKey().Address()
|
||||||
|
|
||||||
|
// Check whether the address is a signer
|
||||||
|
if !isTxSigner(sdk.AccAddress(addr), stdTx.GetSigners()) {
|
||||||
|
fmt.Fprintf(os.Stderr, "WARNING: The generated transaction's intended signer does not match the given signer: '%v'", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if txCtx.AccountNumber == 0 {
|
||||||
|
accNum, err := cliCtx.GetAccountNumber(addr)
|
||||||
|
if err != nil {
|
||||||
|
return signedStdTx, err
|
||||||
|
}
|
||||||
|
txCtx = txCtx.WithAccountNumber(accNum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if txCtx.Sequence == 0 {
|
||||||
|
accSeq, err := cliCtx.GetAccountSequence(addr)
|
||||||
|
if err != nil {
|
||||||
|
return signedStdTx, err
|
||||||
|
}
|
||||||
|
txCtx = txCtx.WithSequence(accSeq)
|
||||||
|
}
|
||||||
|
|
||||||
|
passphrase, err := keys.GetPassphrase(name)
|
||||||
|
if err != nil {
|
||||||
|
return signedStdTx, err
|
||||||
|
}
|
||||||
|
return txCtx.SignStdTx(name, passphrase, stdTx, appendSig)
|
||||||
|
}
|
||||||
|
|
||||||
func adjustGasEstimate(estimate int64, adjustment float64) int64 {
|
func adjustGasEstimate(estimate int64, adjustment float64) int64 {
|
||||||
return int64(adjustment * float64(estimate))
|
return int64(adjustment * float64(estimate))
|
||||||
}
|
}
|
||||||
|
@ -163,3 +207,12 @@ func buildUnsignedStdTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs
|
||||||
}
|
}
|
||||||
return auth.NewStdTx(stdSignMsg.Msgs, stdSignMsg.Fee, nil, stdSignMsg.Memo), nil
|
return auth.NewStdTx(stdSignMsg.Msgs, stdSignMsg.Fee, nil, stdSignMsg.Memo), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isTxSigner(user sdk.AccAddress, signers []sdk.AccAddress) bool {
|
||||||
|
for _, s := range signers {
|
||||||
|
if bytes.Equal(user.Bytes(), s.Bytes()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ package clitest
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -332,7 +333,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
require.Equal(t, " 2 - Apples", proposalsQuery)
|
require.Equal(t, " 2 - Apples", proposalsQuery)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGaiaCLISendGenerateOnly(t *testing.T) {
|
func TestGaiaCLISendGenerateAndSign(t *testing.T) {
|
||||||
chainID, servAddr, port := initializeFixtures(t)
|
chainID, servAddr, port := initializeFixtures(t)
|
||||||
flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID)
|
flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID)
|
||||||
|
|
||||||
|
@ -343,6 +344,7 @@ func TestGaiaCLISendGenerateOnly(t *testing.T) {
|
||||||
tests.WaitForTMStart(port)
|
tests.WaitForTMStart(port)
|
||||||
tests.WaitForNextNBlocksTM(2, port)
|
tests.WaitForNextNBlocksTM(2, port)
|
||||||
|
|
||||||
|
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
|
||||||
barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
|
barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
|
||||||
|
|
||||||
// Test generate sendTx with default gas
|
// Test generate sendTx with default gas
|
||||||
|
@ -376,6 +378,35 @@ func TestGaiaCLISendGenerateOnly(t *testing.T) {
|
||||||
require.Equal(t, msg.Fee.Gas, int64(100))
|
require.Equal(t, msg.Fee.Gas, int64(100))
|
||||||
require.Equal(t, len(msg.Msgs), 1)
|
require.Equal(t, len(msg.Msgs), 1)
|
||||||
require.Equal(t, 0, len(msg.GetSignatures()))
|
require.Equal(t, 0, len(msg.GetSignatures()))
|
||||||
|
|
||||||
|
// Write the output to disk
|
||||||
|
unsignedTxFile := writeToNewTempFile(t, stdout)
|
||||||
|
defer os.Remove(unsignedTxFile.Name())
|
||||||
|
|
||||||
|
// Test sign --print-sigs
|
||||||
|
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||||
|
"gaiacli sign %v --print-sigs %v", flags, unsignedTxFile.Name()))
|
||||||
|
require.True(t, success)
|
||||||
|
require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n", fooAddr.String()), stdout)
|
||||||
|
|
||||||
|
// Test sign
|
||||||
|
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||||
|
"gaiacli sign %v --name=foo %v", flags, unsignedTxFile.Name()), app.DefaultKeyPass)
|
||||||
|
require.True(t, success)
|
||||||
|
msg = unmarshalStdTx(t, stdout)
|
||||||
|
require.Equal(t, len(msg.Msgs), 1)
|
||||||
|
require.Equal(t, 1, len(msg.GetSignatures()))
|
||||||
|
require.Equal(t, fooAddr.String(), msg.GetSigners()[0].String())
|
||||||
|
|
||||||
|
// Write the output to disk
|
||||||
|
signedTxFile := writeToNewTempFile(t, stdout)
|
||||||
|
defer os.Remove(signedTxFile.Name())
|
||||||
|
|
||||||
|
// Test sign --print-signatures
|
||||||
|
success, stdout, _ = executeWriteRetStdStreams(t, fmt.Sprintf(
|
||||||
|
"gaiacli sign %v --print-sigs %v", flags, signedTxFile.Name()))
|
||||||
|
require.True(t, success)
|
||||||
|
require.Equal(t, fmt.Sprintf("Signers:\n 0: %v\n\nSignatures:\n 0: %v\n", fooAddr.String(), fooAddr.String()), stdout)
|
||||||
}
|
}
|
||||||
|
|
||||||
//___________________________________________________________________________________
|
//___________________________________________________________________________________
|
||||||
|
@ -408,6 +439,14 @@ func unmarshalStdTx(t *testing.T, s string) (stdTx auth.StdTx) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeToNewTempFile(t *testing.T, s string) *os.File {
|
||||||
|
fp, err := ioutil.TempFile(os.TempDir(), "cosmos_cli_test_")
|
||||||
|
require.Nil(t, err)
|
||||||
|
_, err = fp.WriteString(s)
|
||||||
|
require.Nil(t, err)
|
||||||
|
return fp
|
||||||
|
}
|
||||||
|
|
||||||
//___________________________________________________________________________________
|
//___________________________________________________________________________________
|
||||||
// executors
|
// executors
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,7 @@ func main() {
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
client.GetCommands(
|
client.GetCommands(
|
||||||
authcmd.GetAccountCmd("acc", cdc, authcmd.GetAccountDecoder(cdc)),
|
authcmd.GetAccountCmd("acc", cdc, authcmd.GetAccountDecoder(cdc)),
|
||||||
|
authcmd.GetSignCommand(cdc, authcmd.GetAccountDecoder(cdc)),
|
||||||
)...)
|
)...)
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
client.PostCommands(
|
client.PostCommands(
|
||||||
|
|
|
@ -229,6 +229,75 @@ Returns on success:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### POST /auth/accounts/sign
|
||||||
|
|
||||||
|
- **URL**: `/auth/sign`
|
||||||
|
- **Functionality**: Sign a transaction without broadcasting it.
|
||||||
|
- Returns on success:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"rest api": "1.0",
|
||||||
|
"code": 200,
|
||||||
|
"error": "",
|
||||||
|
"result": {
|
||||||
|
"type": "auth/StdTx",
|
||||||
|
"value": {
|
||||||
|
"msg": [
|
||||||
|
{
|
||||||
|
"type": "cosmos-sdk/Send",
|
||||||
|
"value": {
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"address": "cosmos1ql4ekxkujf3xllk8h5ldhhgh4ylpu7kwec6q3d",
|
||||||
|
"coins": [
|
||||||
|
{
|
||||||
|
"denom": "steak",
|
||||||
|
"amount": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"address": "cosmos1dhyqhg4px33ed3erqymls0hc7q2lxw9hhfwklj",
|
||||||
|
"coins": [
|
||||||
|
{
|
||||||
|
"denom": "steak",
|
||||||
|
"amount": "1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fee": {
|
||||||
|
"amount": [
|
||||||
|
{
|
||||||
|
"denom": "",
|
||||||
|
"amount": "0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"gas": "2742"
|
||||||
|
},
|
||||||
|
"signatures": [
|
||||||
|
{
|
||||||
|
"pub_key": {
|
||||||
|
"type": "tendermint/PubKeySecp256k1",
|
||||||
|
"value": "A2A/f2IYnrPUMTMqhwN81oas9jurtfcsvxdeLlNw3gGy"
|
||||||
|
},
|
||||||
|
"signature": "MEQCIGVn73y9QLwBa3vmsAD1bs3ygX75Wo+lAFSAUDs431ZPAiBWAf2amyqTCDXE9J87rL9QF9sd5JvVMt7goGSuamPJwg==",
|
||||||
|
"account_number": "1",
|
||||||
|
"sequence": "0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"memo": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## ICS20 - TokenAPI
|
## ICS20 - TokenAPI
|
||||||
|
|
||||||
The TokenAPI exposes all functionality needed to query account balances and send transactions.
|
The TokenAPI exposes all functionality needed to query account balances and send transactions.
|
||||||
|
|
|
@ -147,7 +147,16 @@ gaiacli send \
|
||||||
--chain-id=<chain_id> \
|
--chain-id=<chain_id> \
|
||||||
--name=<key_name> \
|
--name=<key_name> \
|
||||||
--to=<destination_cosmosaccaddr> \
|
--to=<destination_cosmosaccaddr> \
|
||||||
--generate-only
|
--generate-only > unsignedSendTx.json
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now sign the transaction file generated through the `--generate-only` flag by providing your key to the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gaiacli sign \
|
||||||
|
--chain-id=<chain_id> \
|
||||||
|
--name=<key_name>
|
||||||
|
unsignedSendTx.json > signedSendTx.json
|
||||||
```
|
```
|
||||||
|
|
||||||
### Staking
|
### Staking
|
||||||
|
|
|
@ -13,13 +13,13 @@ has to be created and the previous one rendered inactive.
|
||||||
```go
|
```go
|
||||||
type DepositProcedure struct {
|
type DepositProcedure struct {
|
||||||
MinDeposit sdk.Coins // Minimum deposit for a proposal to enter voting period.
|
MinDeposit sdk.Coins // Minimum deposit for a proposal to enter voting period.
|
||||||
MaxDepositPeriod time.Time // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
|
MaxDepositPeriod int64 // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type VotingProcedure struct {
|
type VotingProcedure struct {
|
||||||
VotingPeriod time.Time // Length of the voting period. Initial value: 2 weeks
|
VotingPeriod int64 // Length of the voting period. Initial value: 2 weeks
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ type TallyingProcedure struct {
|
||||||
Threshold sdk.Dec // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5
|
Threshold sdk.Dec // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5
|
||||||
Veto sdk.Dec // Minimum proportion of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
|
Veto sdk.Dec // Minimum proportion of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
|
||||||
GovernancePenalty sdk.Dec // Penalty if validator does not vote
|
GovernancePenalty sdk.Dec // Penalty if validator does not vote
|
||||||
GracePeriod time.Time // If validator entered validator set in this period of blocks before vote ended, governance penalty does not apply
|
GracePeriod int64 // If validator entered validator set in this period of blocks before vote ended, governance penalty does not apply
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -97,10 +97,10 @@ type Proposal struct {
|
||||||
Type ProposalType // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
|
Type ProposalType // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
|
||||||
TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit
|
TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit
|
||||||
Deposits []Deposit // List of deposits on the proposal
|
Deposits []Deposit // List of deposits on the proposal
|
||||||
SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included
|
SubmitBlock int64 // Height of the block where TxGovSubmitProposal was included
|
||||||
Submitter sdk.Address // Address of the submitter
|
Submitter sdk.Address // Address of the submitter
|
||||||
|
|
||||||
VotingStartTime time.Time // Time of the block where MinDeposit was reached. time.Time{} if MinDeposit is not reached
|
VotingStartBlock int64 // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached
|
||||||
CurrentStatus ProposalStatus // Current status of the proposal
|
CurrentStatus ProposalStatus // Current status of the proposal
|
||||||
|
|
||||||
YesVotes sdk.Dec
|
YesVotes sdk.Dec
|
||||||
|
@ -137,7 +137,7 @@ For pseudocode purposes, here are the two function we will use to read or write
|
||||||
* `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the
|
* `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the
|
||||||
`ProposalIDs` of proposals that reached `MinDeposit`. Each round, the oldest
|
`ProposalIDs` of proposals that reached `MinDeposit`. Each round, the oldest
|
||||||
element of `ProposalProcessingQueue` is checked during `BeginBlock` to see if
|
element of `ProposalProcessingQueue` is checked during `BeginBlock` to see if
|
||||||
`CurrentTime == VotingStartTime + activeProcedure.VotingPeriod`. If it is,
|
`CurrentBlock == VotingStartBlock + activeProcedure.VotingPeriod`. If it is,
|
||||||
then the application tallies the votes, compute the votes of each validator and checks if every validator in the valdiator set have voted
|
then the application tallies the votes, compute the votes of each validator and checks if every validator in the valdiator set have voted
|
||||||
and, if not, applies `GovernancePenalty`. If the proposal is accepted, deposits are refunded.
|
and, if not, applies `GovernancePenalty`. If the proposal is accepted, deposits are refunded.
|
||||||
After that proposal is ejected from `ProposalProcessingQueue` and the next element of the queue is evaluated.
|
After that proposal is ejected from `ProposalProcessingQueue` and the next element of the queue is evaluated.
|
||||||
|
@ -159,7 +159,7 @@ And the pseudocode for the `ProposalProcessingQueue`:
|
||||||
proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key
|
proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key
|
||||||
votingProcedure = load(GlobalParams, 'VotingProcedure')
|
votingProcedure = load(GlobalParams, 'VotingProcedure')
|
||||||
|
|
||||||
if (CurrentTime == proposal.VotingStartTime + votingProcedure.VotingPeriod && proposal.CurrentStatus == ProposalStatusActive)
|
if (CurrentBlock == proposal.VotingStartBlock + votingProcedure.VotingPeriod && proposal.CurrentStatus == ProposalStatusActive)
|
||||||
|
|
||||||
// End of voting period, tally
|
// End of voting period, tally
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ And the pseudocode for the `ProposalProcessingQueue`:
|
||||||
|
|
||||||
// Slash validators that did not vote, or update tally if they voted
|
// Slash validators that did not vote, or update tally if they voted
|
||||||
for each validator in validators
|
for each validator in validators
|
||||||
if (validator.bondTime < CurrentTime - tallyingProcedure.GracePeriod)
|
if (validator.bondHeight < CurrentBlock - tallyingProcedure.GracePeriod)
|
||||||
// only slash if validator entered validator set before grace period
|
// only slash if validator entered validator set before grace period
|
||||||
if (!tmpValMap(validator).HasVoted)
|
if (!tmpValMap(validator).HasVoted)
|
||||||
slash validator by tallyingProcedure.GovernancePenalty
|
slash validator by tallyingProcedure.GovernancePenalty
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package cli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
amino "github.com/tendermint/go-amino"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
flagAppend = "append"
|
||||||
|
flagPrintSigs = "print-sigs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetSignCommand returns the sign command
|
||||||
|
func GetSignCommand(codec *amino.Codec, decoder auth.AccountDecoder) *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "sign <file>",
|
||||||
|
Short: "Sign transactions",
|
||||||
|
Long: `Sign transactions created with the --generate-only flag.
|
||||||
|
Read a transaction from <file>, sign it, and print its JSON encoding.`,
|
||||||
|
RunE: makeSignCmd(codec, decoder),
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
}
|
||||||
|
cmd.Flags().String(client.FlagName, "", "Name of private key with which to sign")
|
||||||
|
cmd.Flags().Bool(flagAppend, true, "Append the signature to the existing ones. If disabled, old signatures would be overwritten")
|
||||||
|
cmd.Flags().Bool(flagPrintSigs, false, "Print the addresses that must sign the transaction and those who have already signed it, then exit")
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.Command, args []string) error {
|
||||||
|
return func(cmd *cobra.Command, args []string) (err error) {
|
||||||
|
stdTx, err := readAndUnmarshalStdTx(cdc, args[0])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if viper.GetBool(flagPrintSigs) {
|
||||||
|
printSignatures(stdTx)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
name := viper.GetString(client.FlagName)
|
||||||
|
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(decoder)
|
||||||
|
txCtx := authctx.NewTxContextFromCLI()
|
||||||
|
|
||||||
|
newTx, err := utils.SignStdTx(txCtx, cliCtx, name, stdTx, viper.GetBool(flagAppend))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
json, err := cdc.MarshalJSON(newTx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("%s\n", json)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printSignatures(stdTx auth.StdTx) {
|
||||||
|
fmt.Println("Signers:")
|
||||||
|
for i, signer := range stdTx.GetSigners() {
|
||||||
|
fmt.Printf(" %v: %v\n", i, signer.String())
|
||||||
|
}
|
||||||
|
fmt.Println("")
|
||||||
|
fmt.Println("Signatures:")
|
||||||
|
for i, sig := range stdTx.GetSignatures() {
|
||||||
|
fmt.Printf(" %v: %v\n", i, sdk.AccAddress(sig.Address()).String())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func readAndUnmarshalStdTx(cdc *amino.Codec, filename string) (stdTx auth.StdTx, err error) {
|
||||||
|
var bytes []byte
|
||||||
|
if bytes, err = ioutil.ReadFile(filename); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = cdc.UnmarshalJSON(bytes, &stdTx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -117,24 +117,11 @@ func (ctx TxContext) Build(msgs []sdk.Msg) (auth.StdSignMsg, error) {
|
||||||
// Sign signs a transaction given a name, passphrase, and a single message to
|
// Sign signs a transaction given a name, passphrase, and a single message to
|
||||||
// signed. An error is returned if signing fails.
|
// signed. An error is returned if signing fails.
|
||||||
func (ctx TxContext) Sign(name, passphrase string, msg auth.StdSignMsg) ([]byte, error) {
|
func (ctx TxContext) Sign(name, passphrase string, msg auth.StdSignMsg) ([]byte, error) {
|
||||||
keybase, err := keys.GetKeyBase()
|
sig, err := MakeSignature(name, passphrase, msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return ctx.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, []auth.StdSignature{sig}, msg.Memo))
|
||||||
sig, pubkey, err := keybase.Sign(name, passphrase, msg.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
sigs := []auth.StdSignature{{
|
|
||||||
AccountNumber: msg.AccountNumber,
|
|
||||||
Sequence: msg.Sequence,
|
|
||||||
PubKey: pubkey,
|
|
||||||
Signature: sig,
|
|
||||||
}}
|
|
||||||
|
|
||||||
return ctx.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildAndSign builds a single message to be signed, and signs a transaction
|
// BuildAndSign builds a single message to be signed, and signs a transaction
|
||||||
|
@ -177,3 +164,46 @@ func (ctx TxContext) BuildWithPubKey(name string, msgs []sdk.Msg) ([]byte, error
|
||||||
|
|
||||||
return ctx.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
|
return ctx.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignStdTx appends a signature to a StdTx and returns a copy of a it. If append
|
||||||
|
// is false, it replaces the signatures already attached with the new signature.
|
||||||
|
func (ctx TxContext) SignStdTx(name, passphrase string, stdTx auth.StdTx, appendSig bool) (signedStdTx auth.StdTx, err error) {
|
||||||
|
stdSignature, err := MakeSignature(name, passphrase, auth.StdSignMsg{
|
||||||
|
ChainID: ctx.ChainID,
|
||||||
|
AccountNumber: ctx.AccountNumber,
|
||||||
|
Sequence: ctx.Sequence,
|
||||||
|
Fee: stdTx.Fee,
|
||||||
|
Msgs: stdTx.GetMsgs(),
|
||||||
|
Memo: stdTx.GetMemo(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sigs := stdTx.GetSignatures()
|
||||||
|
if len(sigs) == 0 || !appendSig {
|
||||||
|
sigs = []auth.StdSignature{stdSignature}
|
||||||
|
} else {
|
||||||
|
sigs = append(sigs, stdSignature)
|
||||||
|
}
|
||||||
|
signedStdTx = auth.NewStdTx(stdTx.GetMsgs(), stdTx.Fee, sigs, stdTx.GetMemo())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeSignature builds a StdSignature given key name, passphrase, and a StdSignMsg.
|
||||||
|
func MakeSignature(name, passphrase string, msg auth.StdSignMsg) (sig auth.StdSignature, err error) {
|
||||||
|
keybase, err := keys.GetKeyBase()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sigBytes, pubkey, err := keybase.Sign(name, passphrase, msg.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return auth.StdSignature{
|
||||||
|
AccountNumber: msg.AccountNumber,
|
||||||
|
Sequence: msg.Sequence,
|
||||||
|
PubKey: pubkey,
|
||||||
|
Signature: sigBytes,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,10 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Codec, s
|
||||||
"/accounts/{address}",
|
"/accounts/{address}",
|
||||||
QueryAccountRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), cliCtx),
|
QueryAccountRequestHandlerFn(storeName, cdc, authcmd.GetAccountDecoder(cdc), cliCtx),
|
||||||
).Methods("GET")
|
).Methods("GET")
|
||||||
|
r.HandleFunc(
|
||||||
|
"/sign",
|
||||||
|
SignTxRequestHandlerFn(cdc, cliCtx),
|
||||||
|
).Methods("POST")
|
||||||
}
|
}
|
||||||
|
|
||||||
// query accountREST Handler
|
// query accountREST Handler
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
authctx "github.com/cosmos/cosmos-sdk/x/auth/client/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SignBody defines the properties of a sign request's body.
|
||||||
|
type SignBody struct {
|
||||||
|
Tx auth.StdTx `json:"tx"`
|
||||||
|
LocalAccountName string `json:"name"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
ChainID string `json:"chain_id"`
|
||||||
|
AccountNumber int64 `json:"account_number"`
|
||||||
|
Sequence int64 `json:"sequence"`
|
||||||
|
AppendSig bool `json:"append_sig"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// sign tx REST handler
|
||||||
|
func SignTxRequestHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
|
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var m SignBody
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = cdc.UnmarshalJSON(body, &m)
|
||||||
|
if err != nil {
|
||||||
|
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
txCtx := authctx.TxContext{
|
||||||
|
ChainID: m.ChainID,
|
||||||
|
AccountNumber: m.AccountNumber,
|
||||||
|
Sequence: m.Sequence,
|
||||||
|
}
|
||||||
|
|
||||||
|
signedTx, err := txCtx.SignStdTx(m.LocalAccountName, m.Password, m.Tx, m.AppendSig)
|
||||||
|
if err != nil {
|
||||||
|
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := wire.MarshalJSONIndent(cdc, signedTx)
|
||||||
|
if err != nil {
|
||||||
|
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Write(output)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package gov
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
@ -29,18 +28,12 @@ func TestTickExpiredDepositPeriod(t *testing.T) {
|
||||||
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
||||||
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
||||||
|
|
||||||
newHeader := ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(10)
|
||||||
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
|
|
||||||
ctx = ctx.WithBlockHeader(newHeader)
|
|
||||||
|
|
||||||
EndBlocker(ctx, keeper)
|
EndBlocker(ctx, keeper)
|
||||||
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
||||||
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
||||||
|
|
||||||
newHeader = ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(250)
|
||||||
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod)
|
|
||||||
ctx = ctx.WithBlockHeader(newHeader)
|
|
||||||
|
|
||||||
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
||||||
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
||||||
EndBlocker(ctx, keeper)
|
EndBlocker(ctx, keeper)
|
||||||
|
@ -66,10 +59,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
|
||||||
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
||||||
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
||||||
|
|
||||||
newHeader := ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(10)
|
||||||
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(2) * time.Second)
|
|
||||||
ctx = ctx.WithBlockHeader(newHeader)
|
|
||||||
|
|
||||||
EndBlocker(ctx, keeper)
|
EndBlocker(ctx, keeper)
|
||||||
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
||||||
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
||||||
|
@ -78,20 +68,14 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
|
||||||
res = govHandler(ctx, newProposalMsg2)
|
res = govHandler(ctx, newProposalMsg2)
|
||||||
require.True(t, res.IsOK())
|
require.True(t, res.IsOK())
|
||||||
|
|
||||||
newHeader = ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(205)
|
||||||
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(time.Duration(-1) * time.Second)
|
|
||||||
ctx = ctx.WithBlockHeader(newHeader)
|
|
||||||
|
|
||||||
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
||||||
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
||||||
EndBlocker(ctx, keeper)
|
EndBlocker(ctx, keeper)
|
||||||
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
||||||
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
||||||
|
|
||||||
newHeader = ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(215)
|
||||||
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(5) * time.Second)
|
|
||||||
ctx = ctx.WithBlockHeader(newHeader)
|
|
||||||
|
|
||||||
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
||||||
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
||||||
EndBlocker(ctx, keeper)
|
EndBlocker(ctx, keeper)
|
||||||
|
@ -121,10 +105,7 @@ func TestTickPassedDepositPeriod(t *testing.T) {
|
||||||
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
||||||
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
||||||
|
|
||||||
newHeader := ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(10)
|
||||||
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
|
|
||||||
ctx = ctx.WithBlockHeader(newHeader)
|
|
||||||
|
|
||||||
EndBlocker(ctx, keeper)
|
EndBlocker(ctx, keeper)
|
||||||
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx))
|
||||||
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
|
||||||
|
@ -165,20 +146,14 @@ func TestTickPassedVotingPeriod(t *testing.T) {
|
||||||
var proposalID int64
|
var proposalID int64
|
||||||
keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID)
|
keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID)
|
||||||
|
|
||||||
newHeader := ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(10)
|
||||||
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
|
|
||||||
ctx = ctx.WithBlockHeader(newHeader)
|
|
||||||
|
|
||||||
newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin("steak", 5)})
|
newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin("steak", 5)})
|
||||||
res = govHandler(ctx, newDepositMsg)
|
res = govHandler(ctx, newDepositMsg)
|
||||||
require.True(t, res.IsOK())
|
require.True(t, res.IsOK())
|
||||||
|
|
||||||
EndBlocker(ctx, keeper)
|
EndBlocker(ctx, keeper)
|
||||||
|
|
||||||
newHeader = ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(215)
|
||||||
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod)
|
|
||||||
ctx = ctx.WithBlockHeader(newHeader)
|
|
||||||
|
|
||||||
require.True(t, shouldPopActiveProposalQueue(ctx, keeper))
|
require.True(t, shouldPopActiveProposalQueue(ctx, keeper))
|
||||||
depositsIterator := keeper.GetDeposits(ctx, proposalID)
|
depositsIterator := keeper.GetDeposits(ctx, proposalID)
|
||||||
require.True(t, depositsIterator.Valid())
|
require.True(t, depositsIterator.Valid())
|
||||||
|
@ -222,10 +197,7 @@ func TestSlashing(t *testing.T) {
|
||||||
var proposalID int64
|
var proposalID int64
|
||||||
keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID)
|
keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID)
|
||||||
|
|
||||||
newHeader := ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(10)
|
||||||
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
|
|
||||||
ctx = ctx.WithBlockHeader(newHeader)
|
|
||||||
|
|
||||||
require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus())
|
require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus())
|
||||||
|
|
||||||
newVoteMsg := NewMsgVote(addrs[0], proposalID, OptionYes)
|
newVoteMsg := NewMsgVote(addrs[0], proposalID, OptionYes)
|
||||||
|
@ -234,10 +206,7 @@ func TestSlashing(t *testing.T) {
|
||||||
|
|
||||||
EndBlocker(ctx, keeper)
|
EndBlocker(ctx, keeper)
|
||||||
|
|
||||||
newHeader = ctx.BlockHeader()
|
ctx = ctx.WithBlockHeight(215)
|
||||||
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod)
|
|
||||||
ctx = ctx.WithBlockHeader(newHeader)
|
|
||||||
|
|
||||||
require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus())
|
require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus())
|
||||||
|
|
||||||
EndBlocker(ctx, keeper)
|
EndBlocker(ctx, keeper)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package gov
|
package gov
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -29,10 +27,10 @@ func DefaultGenesisState() GenesisState {
|
||||||
StartingProposalID: 1,
|
StartingProposalID: 1,
|
||||||
DepositProcedure: DepositProcedure{
|
DepositProcedure: DepositProcedure{
|
||||||
MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", 10)},
|
MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", 10)},
|
||||||
MaxDepositPeriod: time.Duration(172800) * time.Second,
|
MaxDepositPeriod: 200,
|
||||||
},
|
},
|
||||||
VotingProcedure: VotingProcedure{
|
VotingProcedure: VotingProcedure{
|
||||||
VotingPeriod: time.Duration(172800) * time.Second,
|
VotingPeriod: 200,
|
||||||
},
|
},
|
||||||
TallyingProcedure: TallyingProcedure{
|
TallyingProcedure: TallyingProcedure{
|
||||||
Threshold: sdk.NewDecWithPrec(5, 1),
|
Threshold: sdk.NewDecWithPrec(5, 1),
|
||||||
|
|
|
@ -122,9 +122,9 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
|
||||||
for shouldPopActiveProposalQueue(ctx, keeper) {
|
for shouldPopActiveProposalQueue(ctx, keeper) {
|
||||||
activeProposal := keeper.ActiveProposalQueuePop(ctx)
|
activeProposal := keeper.ActiveProposalQueuePop(ctx)
|
||||||
|
|
||||||
proposalStartTime := activeProposal.GetVotingStartTime()
|
proposalStartBlock := activeProposal.GetVotingStartBlock()
|
||||||
votingPeriod := keeper.GetVotingProcedure(ctx).VotingPeriod
|
votingPeriod := keeper.GetVotingProcedure(ctx).VotingPeriod
|
||||||
if ctx.BlockHeader().Time.Before(proposalStartTime.Add(votingPeriod)) {
|
if ctx.BlockHeight() < proposalStartBlock+votingPeriod {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ func shouldPopInactiveProposalQueue(ctx sdk.Context, keeper Keeper) bool {
|
||||||
return false
|
return false
|
||||||
} else if peekProposal.GetStatus() != StatusDepositPeriod {
|
} else if peekProposal.GetStatus() != StatusDepositPeriod {
|
||||||
return true
|
return true
|
||||||
} else if !ctx.BlockHeader().Time.Before(peekProposal.GetSubmitTime().Add(depositProcedure.MaxDepositPeriod)) {
|
} else if ctx.BlockHeight() >= peekProposal.GetSubmitBlock()+depositProcedure.MaxDepositPeriod {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -184,7 +184,7 @@ func shouldPopActiveProposalQueue(ctx sdk.Context, keeper Keeper) bool {
|
||||||
|
|
||||||
if peekProposal == nil {
|
if peekProposal == nil {
|
||||||
return false
|
return false
|
||||||
} else if !ctx.BlockHeader().Time.Before(peekProposal.GetVotingStartTime().Add(votingProcedure.VotingPeriod)) {
|
} else if ctx.BlockHeight() >= peekProposal.GetVotingStartBlock()+votingProcedure.VotingPeriod {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -73,7 +73,8 @@ func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description
|
||||||
Status: StatusDepositPeriod,
|
Status: StatusDepositPeriod,
|
||||||
TallyResult: EmptyTallyResult(),
|
TallyResult: EmptyTallyResult(),
|
||||||
TotalDeposit: sdk.Coins{},
|
TotalDeposit: sdk.Coins{},
|
||||||
SubmitTime: ctx.BlockHeader().Time,
|
SubmitBlock: ctx.BlockHeight(),
|
||||||
|
VotingStartBlock: -1, // TODO: Make Time
|
||||||
}
|
}
|
||||||
keeper.SetProposal(ctx, proposal)
|
keeper.SetProposal(ctx, proposal)
|
||||||
keeper.InactiveProposalQueuePush(ctx, proposal)
|
keeper.InactiveProposalQueuePush(ctx, proposal)
|
||||||
|
@ -199,7 +200,7 @@ func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID int64, e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
|
func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
|
||||||
proposal.SetVotingStartTime(ctx.BlockHeader().Time)
|
proposal.SetVotingStartBlock(ctx.BlockHeight())
|
||||||
proposal.SetStatus(StatusVotingPeriod)
|
proposal.SetStatus(StatusVotingPeriod)
|
||||||
keeper.SetProposal(ctx, proposal)
|
keeper.SetProposal(ctx, proposal)
|
||||||
keeper.ActiveProposalQueuePush(ctx, proposal)
|
keeper.ActiveProposalQueuePush(ctx, proposal)
|
||||||
|
|
|
@ -2,7 +2,6 @@ package gov
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
@ -46,12 +45,12 @@ func TestActivateVotingPeriod(t *testing.T) {
|
||||||
|
|
||||||
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
|
||||||
|
|
||||||
require.True(t, proposal.GetVotingStartTime().Equal(time.Time{}))
|
require.Equal(t, int64(-1), proposal.GetVotingStartBlock())
|
||||||
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
|
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
|
||||||
|
|
||||||
keeper.activateVotingPeriod(ctx, proposal)
|
keeper.activateVotingPeriod(ctx, proposal)
|
||||||
|
|
||||||
require.True(t, proposal.GetVotingStartTime().Equal(ctx.BlockHeader().Time))
|
require.Equal(t, proposal.GetVotingStartBlock(), ctx.BlockHeight())
|
||||||
require.Equal(t, proposal.GetProposalID(), keeper.ActiveProposalQueuePeek(ctx).GetProposalID())
|
require.Equal(t, proposal.GetProposalID(), keeper.ActiveProposalQueuePeek(ctx).GetProposalID())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +77,7 @@ func TestDeposits(t *testing.T) {
|
||||||
// Check no deposits at beginning
|
// Check no deposits at beginning
|
||||||
deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1])
|
deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1])
|
||||||
require.False(t, found)
|
require.False(t, found)
|
||||||
require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(time.Time{}))
|
require.Equal(t, keeper.GetProposal(ctx, proposalID).GetVotingStartBlock(), int64(-1))
|
||||||
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
|
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
|
||||||
|
|
||||||
// Check first deposit
|
// Check first deposit
|
||||||
|
@ -115,7 +114,7 @@ func TestDeposits(t *testing.T) {
|
||||||
require.Equal(t, addr1Initial.Minus(fourSteak), keeper.ck.GetCoins(ctx, addrs[1]))
|
require.Equal(t, addr1Initial.Minus(fourSteak), keeper.ck.GetCoins(ctx, addrs[1]))
|
||||||
|
|
||||||
// Check that proposal moved to voting period
|
// Check that proposal moved to voting period
|
||||||
require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(ctx.BlockHeader().Time))
|
require.Equal(t, ctx.BlockHeight(), keeper.GetProposal(ctx, proposalID).GetVotingStartBlock())
|
||||||
require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx))
|
require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx))
|
||||||
require.Equal(t, proposalID, keeper.ActiveProposalQueuePeek(ctx).GetProposalID())
|
require.Equal(t, proposalID, keeper.ActiveProposalQueuePeek(ctx).GetProposalID())
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
package gov
|
package gov
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Procedure around Deposits for governance
|
// Procedure around Deposits for governance
|
||||||
type DepositProcedure struct {
|
type DepositProcedure struct {
|
||||||
MinDeposit sdk.Coins `json:"min_deposit"` // Minimum deposit for a proposal to enter voting period.
|
MinDeposit sdk.Coins `json:"min_deposit"` // Minimum deposit for a proposal to enter voting period.
|
||||||
MaxDepositPeriod time.Duration `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
|
MaxDepositPeriod int64 `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
|
||||||
}
|
}
|
||||||
|
|
||||||
// Procedure around Tallying votes in governance
|
// Procedure around Tallying votes in governance
|
||||||
|
@ -21,5 +19,5 @@ type TallyingProcedure struct {
|
||||||
|
|
||||||
// Procedure around Voting in governance
|
// Procedure around Voting in governance
|
||||||
type VotingProcedure struct {
|
type VotingProcedure struct {
|
||||||
VotingPeriod time.Duration `json:"voting_period"` // Length of the voting period.
|
VotingPeriod int64 `json:"voting_period"` // Length of the voting period.
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package gov
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
@ -31,14 +30,14 @@ type Proposal interface {
|
||||||
GetTallyResult() TallyResult
|
GetTallyResult() TallyResult
|
||||||
SetTallyResult(TallyResult)
|
SetTallyResult(TallyResult)
|
||||||
|
|
||||||
GetSubmitTime() time.Time
|
GetSubmitBlock() int64
|
||||||
SetSubmitTime(time.Time)
|
SetSubmitBlock(int64)
|
||||||
|
|
||||||
GetTotalDeposit() sdk.Coins
|
GetTotalDeposit() sdk.Coins
|
||||||
SetTotalDeposit(sdk.Coins)
|
SetTotalDeposit(sdk.Coins)
|
||||||
|
|
||||||
GetVotingStartTime() time.Time
|
GetVotingStartBlock() int64
|
||||||
SetVotingStartTime(time.Time)
|
SetVotingStartBlock(int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks if two proposals are equal
|
// checks if two proposals are equal
|
||||||
|
@ -49,9 +48,9 @@ func ProposalEqual(proposalA Proposal, proposalB Proposal) bool {
|
||||||
proposalA.GetProposalType() == proposalB.GetProposalType() &&
|
proposalA.GetProposalType() == proposalB.GetProposalType() &&
|
||||||
proposalA.GetStatus() == proposalB.GetStatus() &&
|
proposalA.GetStatus() == proposalB.GetStatus() &&
|
||||||
proposalA.GetTallyResult().Equals(proposalB.GetTallyResult()) &&
|
proposalA.GetTallyResult().Equals(proposalB.GetTallyResult()) &&
|
||||||
proposalA.GetSubmitTime().Equal(proposalB.GetSubmitTime()) &&
|
proposalA.GetSubmitBlock() == proposalB.GetSubmitBlock() &&
|
||||||
proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit()) &&
|
proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit()) &&
|
||||||
proposalA.GetVotingStartTime().Equal(proposalB.GetVotingStartTime()) {
|
proposalA.GetVotingStartBlock() == proposalB.GetVotingStartBlock() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -68,10 +67,10 @@ type TextProposal struct {
|
||||||
Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected}
|
Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected}
|
||||||
TallyResult TallyResult `json:"tally_result"` // Result of Tallys
|
TallyResult TallyResult `json:"tally_result"` // Result of Tallys
|
||||||
|
|
||||||
SubmitTime time.Time `json:"submit_block"` // Height of the block where TxGovSubmitProposal was included
|
SubmitBlock int64 `json:"submit_block"` // Height of the block where TxGovSubmitProposal was included
|
||||||
TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit
|
TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit
|
||||||
|
|
||||||
VotingStartTime time.Time `json:"voting_start_block"` // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached
|
VotingStartBlock int64 `json:"voting_start_block"` // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements Proposal Interface
|
// Implements Proposal Interface
|
||||||
|
@ -90,13 +89,13 @@ func (tp TextProposal) GetStatus() ProposalStatus { return tp.S
|
||||||
func (tp *TextProposal) SetStatus(status ProposalStatus) { tp.Status = status }
|
func (tp *TextProposal) SetStatus(status ProposalStatus) { tp.Status = status }
|
||||||
func (tp TextProposal) GetTallyResult() TallyResult { return tp.TallyResult }
|
func (tp TextProposal) GetTallyResult() TallyResult { return tp.TallyResult }
|
||||||
func (tp *TextProposal) SetTallyResult(tallyResult TallyResult) { tp.TallyResult = tallyResult }
|
func (tp *TextProposal) SetTallyResult(tallyResult TallyResult) { tp.TallyResult = tallyResult }
|
||||||
func (tp TextProposal) GetSubmitTime() time.Time { return tp.SubmitTime }
|
func (tp TextProposal) GetSubmitBlock() int64 { return tp.SubmitBlock }
|
||||||
func (tp *TextProposal) SetSubmitTime(submitTime time.Time) { tp.SubmitTime = submitTime }
|
func (tp *TextProposal) SetSubmitBlock(submitBlock int64) { tp.SubmitBlock = submitBlock }
|
||||||
func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit }
|
func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit }
|
||||||
func (tp *TextProposal) SetTotalDeposit(totalDeposit sdk.Coins) { tp.TotalDeposit = totalDeposit }
|
func (tp *TextProposal) SetTotalDeposit(totalDeposit sdk.Coins) { tp.TotalDeposit = totalDeposit }
|
||||||
func (tp TextProposal) GetVotingStartTime() time.Time { return tp.VotingStartTime }
|
func (tp TextProposal) GetVotingStartBlock() int64 { return tp.VotingStartBlock }
|
||||||
func (tp *TextProposal) SetVotingStartTime(votingStartTime time.Time) {
|
func (tp *TextProposal) SetVotingStartBlock(votingStartBlock int64) {
|
||||||
tp.VotingStartTime = votingStartTime
|
tp.VotingStartBlock = votingStartBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------
|
//-----------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue