Merge branch 'develop' of https://github.com/cosmos/cosmos-sdk into develop
This commit is contained in:
commit
c0c31629c0
49
CHANGELOG.md
49
CHANGELOG.md
|
@ -1,6 +1,48 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## 0.16.0 (TBD)
|
## 0.18.0 (TBD)
|
||||||
|
|
||||||
|
FEATURES
|
||||||
|
|
||||||
|
* [x/auth] Added ability to change pubkey to auth module
|
||||||
|
* [baseapp] baseapp now has settable functions for filtering peers by address/port & public key
|
||||||
|
* [sdk] Gas consumption is now measured as transactions are executed
|
||||||
|
* Transactions which run out of gas stop execution and revert state changes
|
||||||
|
* A "simulate" query has been added to determine how much gas a transaction will need
|
||||||
|
* Modules can include their own gas costs for execution of particular message types
|
||||||
|
|
||||||
|
## 0.17.1 (May 17, 2018)
|
||||||
|
|
||||||
|
Update to Tendermint v0.19.4 (fixes a consensus bug and improves logging)
|
||||||
|
|
||||||
|
## 0.17.0 (May 15, 2018)
|
||||||
|
|
||||||
|
BREAKING CHANGES
|
||||||
|
|
||||||
|
* [stake] MarshalJSON -> MarshalBinary
|
||||||
|
|
||||||
|
FEATURES
|
||||||
|
|
||||||
|
* [gaiacli] Support queries for candidates, delegator-bonds
|
||||||
|
* [gaiad] Added `gaiad export` command to export current state to JSON
|
||||||
|
* [x/bank] Tx tags with sender/recipient for indexing & later retrieval
|
||||||
|
* [x/stake] Tx tags with delegator/candidate for delegation & unbonding, and candidate info for declare candidate / edit candidacy
|
||||||
|
|
||||||
|
IMPROVEMENTS
|
||||||
|
|
||||||
|
* [gaiad] Update for Tendermint v0.19.3 (improve `/dump_consensus_state` and add
|
||||||
|
`/consensus_state`)
|
||||||
|
* [spec/ibc] Added spec!
|
||||||
|
* [spec/stake] Cleanup structure, include details about slashing and
|
||||||
|
auto-unbonding
|
||||||
|
* [spec/governance] Fixup some names and pseudocode
|
||||||
|
* NOTE: specs are still a work-in-progress ...
|
||||||
|
|
||||||
|
BUG FIXES
|
||||||
|
|
||||||
|
* Auto-sequencing now works correctly
|
||||||
|
|
||||||
|
## 0.16.0 (May 14th, 2018)
|
||||||
|
|
||||||
BREAKING CHANGES
|
BREAKING CHANGES
|
||||||
|
|
||||||
|
@ -15,10 +57,10 @@ BREAKING CHANGES
|
||||||
* gaiad init now requires use of `--name` flag
|
* gaiad init now requires use of `--name` flag
|
||||||
* Removed Get from Msg interface
|
* Removed Get from Msg interface
|
||||||
* types/rational now extends big.Rat
|
* types/rational now extends big.Rat
|
||||||
|
* Queries against the store must be prefixed with the path "/store"
|
||||||
|
|
||||||
FEATURES:
|
FEATURES:
|
||||||
|
|
||||||
* Added `gaiad export` command, which exports genesis information & current state
|
|
||||||
* Gaia stake commands include, DeclareCandidacy, EditCandidacy, Delegate, Unbond
|
* Gaia stake commands include, DeclareCandidacy, EditCandidacy, Delegate, Unbond
|
||||||
* MountStoreWithDB without providing a custom store works.
|
* MountStoreWithDB without providing a custom store works.
|
||||||
* Repo is now lint compliant / GoMetaLinter with tendermint-lint integrated into CI
|
* Repo is now lint compliant / GoMetaLinter with tendermint-lint integrated into CI
|
||||||
|
@ -30,12 +72,9 @@ FEATURES:
|
||||||
* Context now has access to the application-configured logger
|
* Context now has access to the application-configured logger
|
||||||
* Add (non-proof) subspace query helper functions
|
* Add (non-proof) subspace query helper functions
|
||||||
* Add more staking query functions: candidates, delegator-bonds
|
* Add more staking query functions: candidates, delegator-bonds
|
||||||
* Bank module now tags transactions with sender/recipient for indexing & later retrieval
|
|
||||||
* Stake module now tags transactions with delegator/candidate for delegation & unbonding, and candidate info for declare candidate / edit candidacy
|
|
||||||
|
|
||||||
BUG FIXES
|
BUG FIXES
|
||||||
* Gaia now uses stake, ported from github.com/cosmos/gaia
|
* Gaia now uses stake, ported from github.com/cosmos/gaia
|
||||||
* Auto-sequencing now works correctly
|
|
||||||
|
|
||||||
## 0.15.1 (April 29, 2018)
|
## 0.15.1 (April 29, 2018)
|
||||||
|
|
||||||
|
|
|
@ -87,14 +87,14 @@
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/gorilla/context"
|
name = "github.com/gorilla/context"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "1ea25387ff6f684839d82767c1733ff4d4d15d0a"
|
revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42"
|
||||||
version = "v1.1"
|
version = "v1.1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/gorilla/mux"
|
name = "github.com/gorilla/mux"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "53c1911da2b537f792e7cafcb446b05ffe33b996"
|
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
|
||||||
version = "v1.6.1"
|
version = "v1.6.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/gorilla/websocket"
|
name = "github.com/gorilla/websocket"
|
||||||
|
@ -159,7 +159,7 @@
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/mitchellh/mapstructure"
|
name = "github.com/mitchellh/mapstructure"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "00c29f56e2386353d58c599509e8dc3801b0d716"
|
revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/pelletier/go-toml"
|
name = "github.com/pelletier/go-toml"
|
||||||
|
@ -183,7 +183,7 @@
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/rcrowley/go-metrics"
|
name = "github.com/rcrowley/go-metrics"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "d932a24a8ccb8fcadc993e5c6c58f93dac168294"
|
revision = "e2704e165165ec55d062f5919b4b29494e9fa790"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/spf13/afero"
|
name = "github.com/spf13/afero"
|
||||||
|
@ -250,7 +250,7 @@
|
||||||
"leveldb/table",
|
"leveldb/table",
|
||||||
"leveldb/util"
|
"leveldb/util"
|
||||||
]
|
]
|
||||||
revision = "714f901b98fdb3aa954b4193d8cbd64a28d80cad"
|
revision = "9637fa0b2f0db13c99d899b91007edb7df4610b7"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/tendermint/abci"
|
name = "github.com/tendermint/abci"
|
||||||
|
@ -323,7 +323,6 @@
|
||||||
"p2p",
|
"p2p",
|
||||||
"p2p/conn",
|
"p2p/conn",
|
||||||
"p2p/pex",
|
"p2p/pex",
|
||||||
"p2p/trust",
|
|
||||||
"p2p/upnp",
|
"p2p/upnp",
|
||||||
"proxy",
|
"proxy",
|
||||||
"rpc/client",
|
"rpc/client",
|
||||||
|
@ -342,8 +341,8 @@
|
||||||
"types/priv_validator",
|
"types/priv_validator",
|
||||||
"version"
|
"version"
|
||||||
]
|
]
|
||||||
revision = "26f633ed48441f72895b710f0e87b7b6c6791066"
|
revision = "19ccd1842fe5efffcc2ff32e6cfc127ca0cd1f9b"
|
||||||
version = "v0.19.1"
|
version = "v0.19.4-rc0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/tendermint/tmlibs"
|
name = "github.com/tendermint/tmlibs"
|
||||||
|
@ -360,8 +359,8 @@
|
||||||
"pubsub",
|
"pubsub",
|
||||||
"pubsub/query"
|
"pubsub/query"
|
||||||
]
|
]
|
||||||
revision = "d94e312673e16a11ea55d742cefb3e331228f898"
|
revision = "cc5f287c4798ffe88c04d02df219ecb6932080fd"
|
||||||
version = "v0.8.2"
|
version = "v0.8.3-rc0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -377,7 +376,7 @@
|
||||||
"ripemd160",
|
"ripemd160",
|
||||||
"salsa20/salsa"
|
"salsa20/salsa"
|
||||||
]
|
]
|
||||||
revision = "b49d69b5da943f7ef3c9cf91c8777c1f78a0cc3c"
|
revision = "2fc4c88bf43f0ea5ea305eae2b7af24b2cc93287"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
@ -389,16 +388,15 @@
|
||||||
"http2/hpack",
|
"http2/hpack",
|
||||||
"idna",
|
"idna",
|
||||||
"internal/timeseries",
|
"internal/timeseries",
|
||||||
"lex/httplex",
|
|
||||||
"trace"
|
"trace"
|
||||||
]
|
]
|
||||||
revision = "5f9ae10d9af5b1c89ae6904293b14b064d4ada23"
|
revision = "2491c5de3490fced2f6cff376127c667efeed857"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = ["unix"]
|
packages = ["unix"]
|
||||||
revision = "cbbc999da32df943dac6cd71eb3ee39e1d7838b9"
|
revision = "7c87d13f8e835d2fb3a70a2912c811ed0c1d241b"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
|
@ -422,10 +420,9 @@
|
||||||
version = "v0.3.0"
|
version = "v0.3.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
|
||||||
name = "google.golang.org/genproto"
|
name = "google.golang.org/genproto"
|
||||||
packages = ["googleapis/rpc/status"]
|
packages = ["googleapis/rpc/status"]
|
||||||
revision = "86e600f69ee4704c6efbf6a2a40a5c10700e76c2"
|
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "google.golang.org/grpc"
|
name = "google.golang.org/grpc"
|
||||||
|
@ -460,6 +457,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "fad966346d3b6042faf2bf793168b6ce9a8ff59ae207b7ad57008ead0f3ff7d4"
|
inputs-digest = "8c37fee3e6d3034b865c68185f4796223fe53b1b0ee4a305adbee5f53c50bfce"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
@ -70,11 +70,16 @@
|
||||||
|
|
||||||
[[constraint]]
|
[[constraint]]
|
||||||
name = "github.com/tendermint/tendermint"
|
name = "github.com/tendermint/tendermint"
|
||||||
version = "0.19.1"
|
version = "0.19.4-rc0"
|
||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "github.com/tendermint/tmlibs"
|
name = "github.com/tendermint/tmlibs"
|
||||||
version = "~0.8.2-rc1"
|
version = "~0.8.3-rc0"
|
||||||
|
|
||||||
|
# this got updated and broke, so locked to an old working commit ...
|
||||||
|
[[override]]
|
||||||
|
name = "google.golang.org/genproto"
|
||||||
|
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"
|
||||||
|
|
||||||
[prune]
|
[prune]
|
||||||
go-tests = true
|
go-tests = true
|
||||||
|
|
|
@ -16,7 +16,7 @@ master | [
|
**Note**: Requires [Go 1.10+](https://golang.org/dl/)
|
||||||
|
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
|
@ -3,6 +3,7 @@ package baseapp
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
@ -22,11 +23,24 @@ import (
|
||||||
// and to avoid affecting the Merkle root.
|
// and to avoid affecting the Merkle root.
|
||||||
var dbHeaderKey = []byte("header")
|
var dbHeaderKey = []byte("header")
|
||||||
|
|
||||||
|
// Enum mode for app.runTx
|
||||||
|
type runTxMode uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Check a transaction
|
||||||
|
runTxModeCheck runTxMode = iota
|
||||||
|
// Simulate a transaction
|
||||||
|
runTxModeSimulate runTxMode = iota
|
||||||
|
// Deliver a transaction
|
||||||
|
runTxModeDeliver runTxMode = iota
|
||||||
|
)
|
||||||
|
|
||||||
// The ABCI application
|
// The ABCI application
|
||||||
type BaseApp struct {
|
type BaseApp struct {
|
||||||
// initialized on creation
|
// initialized on creation
|
||||||
Logger log.Logger
|
Logger log.Logger
|
||||||
name string // application name from abci.Info
|
name string // application name from abci.Info
|
||||||
|
cdc *wire.Codec // Amino codec
|
||||||
db dbm.DB // common DB backend
|
db dbm.DB // common DB backend
|
||||||
cms sdk.CommitMultiStore // Main (uncached) state
|
cms sdk.CommitMultiStore // Main (uncached) state
|
||||||
router Router // handle any kind of message
|
router Router // handle any kind of message
|
||||||
|
@ -40,6 +54,8 @@ type BaseApp struct {
|
||||||
initChainer sdk.InitChainer // initialize state with validators and state blob
|
initChainer sdk.InitChainer // initialize state with validators and state blob
|
||||||
beginBlocker sdk.BeginBlocker // logic to run before any txs
|
beginBlocker sdk.BeginBlocker // logic to run before any txs
|
||||||
endBlocker sdk.EndBlocker // logic to run after all txs, and to determine valset changes
|
endBlocker sdk.EndBlocker // logic to run after all txs, and to determine valset changes
|
||||||
|
addrPeerFilter sdk.PeerFilter // filter peers by address and port
|
||||||
|
pubkeyPeerFilter sdk.PeerFilter // filter peers by public key
|
||||||
|
|
||||||
//--------------------
|
//--------------------
|
||||||
// Volatile
|
// Volatile
|
||||||
|
@ -61,6 +77,7 @@ func NewBaseApp(name string, cdc *wire.Codec, logger log.Logger, db dbm.DB) *Bas
|
||||||
app := &BaseApp{
|
app := &BaseApp{
|
||||||
Logger: logger,
|
Logger: logger,
|
||||||
name: name,
|
name: name,
|
||||||
|
cdc: cdc,
|
||||||
db: db,
|
db: db,
|
||||||
cms: store.NewCommitMultiStore(db),
|
cms: store.NewCommitMultiStore(db),
|
||||||
router: NewRouter(),
|
router: NewRouter(),
|
||||||
|
@ -137,6 +154,12 @@ func (app *BaseApp) SetEndBlocker(endBlocker sdk.EndBlocker) {
|
||||||
func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) {
|
func (app *BaseApp) SetAnteHandler(ah sdk.AnteHandler) {
|
||||||
app.anteHandler = ah
|
app.anteHandler = ah
|
||||||
}
|
}
|
||||||
|
func (app *BaseApp) SetAddrPeerFilter(pf sdk.PeerFilter) {
|
||||||
|
app.addrPeerFilter = pf
|
||||||
|
}
|
||||||
|
func (app *BaseApp) SetPubKeyPeerFilter(pf sdk.PeerFilter) {
|
||||||
|
app.pubkeyPeerFilter = pf
|
||||||
|
}
|
||||||
func (app *BaseApp) Router() Router { return app.router }
|
func (app *BaseApp) Router() Router { return app.router }
|
||||||
|
|
||||||
// load latest application version
|
// load latest application version
|
||||||
|
@ -277,16 +300,75 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter peers by address / port
|
||||||
|
func (app *BaseApp) FilterPeerByAddrPort(info string) abci.ResponseQuery {
|
||||||
|
if app.addrPeerFilter != nil {
|
||||||
|
return app.addrPeerFilter(info)
|
||||||
|
}
|
||||||
|
return abci.ResponseQuery{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter peers by public key
|
||||||
|
func (app *BaseApp) FilterPeerByPubKey(info string) abci.ResponseQuery {
|
||||||
|
if app.pubkeyPeerFilter != nil {
|
||||||
|
return app.pubkeyPeerFilter(info)
|
||||||
|
}
|
||||||
|
return abci.ResponseQuery{}
|
||||||
|
}
|
||||||
|
|
||||||
// Implements ABCI.
|
// Implements ABCI.
|
||||||
// Delegates to CommitMultiStore if it implements Queryable
|
// Delegates to CommitMultiStore if it implements Queryable
|
||||||
func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
|
func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
|
||||||
|
path := strings.Split(req.Path, "/")
|
||||||
|
// first element is empty string
|
||||||
|
if len(path) > 0 && path[0] == "" {
|
||||||
|
path = path[1:]
|
||||||
|
}
|
||||||
|
// "/app" prefix for special application queries
|
||||||
|
if len(path) >= 2 && path[0] == "app" {
|
||||||
|
var result sdk.Result
|
||||||
|
switch path[1] {
|
||||||
|
case "simulate":
|
||||||
|
txBytes := req.Data
|
||||||
|
tx, err := app.txDecoder(txBytes)
|
||||||
|
if err != nil {
|
||||||
|
result = err.Result()
|
||||||
|
} else {
|
||||||
|
result = app.Simulate(tx)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
result = sdk.ErrUnknownRequest(fmt.Sprintf("Unknown query: %s", path)).Result()
|
||||||
|
}
|
||||||
|
value := app.cdc.MustMarshalBinary(result)
|
||||||
|
return abci.ResponseQuery{
|
||||||
|
Code: uint32(sdk.ABCICodeOK),
|
||||||
|
Value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// "/store" prefix for store queries
|
||||||
|
if len(path) >= 1 && path[0] == "store" {
|
||||||
queryable, ok := app.cms.(sdk.Queryable)
|
queryable, ok := app.cms.(sdk.Queryable)
|
||||||
if !ok {
|
if !ok {
|
||||||
msg := "application doesn't support queries"
|
msg := "multistore doesn't support queries"
|
||||||
return sdk.ErrUnknownRequest(msg).QueryResult()
|
return sdk.ErrUnknownRequest(msg).QueryResult()
|
||||||
}
|
}
|
||||||
|
req.Path = "/" + strings.Join(path[1:], "/")
|
||||||
return queryable.Query(req)
|
return queryable.Query(req)
|
||||||
}
|
}
|
||||||
|
// "/p2p" prefix for p2p queries
|
||||||
|
if len(path) >= 4 && path[0] == "p2p" {
|
||||||
|
if path[1] == "filter" {
|
||||||
|
if path[2] == "addr" {
|
||||||
|
return app.FilterPeerByAddrPort(path[3])
|
||||||
|
}
|
||||||
|
if path[2] == "pubkey" {
|
||||||
|
return app.FilterPeerByPubKey(path[3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msg := "unknown query path"
|
||||||
|
return sdk.ErrUnknownRequest(msg).QueryResult()
|
||||||
|
}
|
||||||
|
|
||||||
// Implements ABCI
|
// Implements ABCI
|
||||||
func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) {
|
func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) {
|
||||||
|
@ -312,7 +394,7 @@ func (app *BaseApp) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result = err.Result()
|
result = err.Result()
|
||||||
} else {
|
} else {
|
||||||
result = app.runTx(true, txBytes, tx)
|
result = app.runTx(runTxModeCheck, txBytes, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return abci.ResponseCheckTx{
|
return abci.ResponseCheckTx{
|
||||||
|
@ -320,6 +402,7 @@ func (app *BaseApp) CheckTx(txBytes []byte) (res abci.ResponseCheckTx) {
|
||||||
Data: result.Data,
|
Data: result.Data,
|
||||||
Log: result.Log,
|
Log: result.Log,
|
||||||
GasWanted: result.GasWanted,
|
GasWanted: result.GasWanted,
|
||||||
|
GasUsed: result.GasUsed,
|
||||||
Fee: cmn.KI64Pair{
|
Fee: cmn.KI64Pair{
|
||||||
[]byte(result.FeeDenom),
|
[]byte(result.FeeDenom),
|
||||||
result.FeeAmount,
|
result.FeeAmount,
|
||||||
|
@ -336,7 +419,7 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result = err.Result()
|
result = err.Result()
|
||||||
} else {
|
} else {
|
||||||
result = app.runTx(false, txBytes, tx)
|
result = app.runTx(runTxModeDeliver, txBytes, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// After-handler hooks.
|
// After-handler hooks.
|
||||||
|
@ -360,21 +443,34 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
|
||||||
|
|
||||||
// nolint - Mostly for testing
|
// nolint - Mostly for testing
|
||||||
func (app *BaseApp) Check(tx sdk.Tx) (result sdk.Result) {
|
func (app *BaseApp) Check(tx sdk.Tx) (result sdk.Result) {
|
||||||
return app.runTx(true, nil, tx)
|
return app.runTx(runTxModeCheck, nil, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint - full tx execution
|
||||||
|
func (app *BaseApp) Simulate(tx sdk.Tx) (result sdk.Result) {
|
||||||
|
return app.runTx(runTxModeSimulate, nil, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
func (app *BaseApp) Deliver(tx sdk.Tx) (result sdk.Result) {
|
func (app *BaseApp) Deliver(tx sdk.Tx) (result sdk.Result) {
|
||||||
return app.runTx(false, nil, tx)
|
return app.runTx(runTxModeDeliver, nil, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// txBytes may be nil in some cases, eg. in tests.
|
// txBytes may be nil in some cases, eg. in tests.
|
||||||
// Also, in the future we may support "internal" transactions.
|
// Also, in the future we may support "internal" transactions.
|
||||||
func (app *BaseApp) runTx(isCheckTx bool, txBytes []byte, tx sdk.Tx) (result sdk.Result) {
|
func (app *BaseApp) runTx(mode runTxMode, txBytes []byte, tx sdk.Tx) (result sdk.Result) {
|
||||||
// Handle any panics.
|
// Handle any panics.
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
switch r.(type) {
|
||||||
|
case sdk.ErrorOutOfGas:
|
||||||
|
log := fmt.Sprintf("Out of gas in location: %v", r.(sdk.ErrorOutOfGas).Descriptor)
|
||||||
|
result = sdk.ErrOutOfGas(log).Result()
|
||||||
|
default:
|
||||||
log := fmt.Sprintf("Recovered: %v\nstack:\n%v", r, string(debug.Stack()))
|
log := fmt.Sprintf("Recovered: %v\nstack:\n%v", r, string(debug.Stack()))
|
||||||
result = sdk.ErrInternal(log).Result()
|
result = sdk.ErrInternal(log).Result()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Get the Msg.
|
// Get the Msg.
|
||||||
|
@ -392,12 +488,17 @@ func (app *BaseApp) runTx(isCheckTx bool, txBytes []byte, tx sdk.Tx) (result sdk
|
||||||
|
|
||||||
// Get the context
|
// Get the context
|
||||||
var ctx sdk.Context
|
var ctx sdk.Context
|
||||||
if isCheckTx {
|
if mode == runTxModeCheck || mode == runTxModeSimulate {
|
||||||
ctx = app.checkState.ctx.WithTxBytes(txBytes)
|
ctx = app.checkState.ctx.WithTxBytes(txBytes)
|
||||||
} else {
|
} else {
|
||||||
ctx = app.deliverState.ctx.WithTxBytes(txBytes)
|
ctx = app.deliverState.ctx.WithTxBytes(txBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Simulate a DeliverTx for gas calculation
|
||||||
|
if mode == runTxModeSimulate {
|
||||||
|
ctx = ctx.WithIsCheckTx(false)
|
||||||
|
}
|
||||||
|
|
||||||
// Run the ante handler.
|
// Run the ante handler.
|
||||||
if app.anteHandler != nil {
|
if app.anteHandler != nil {
|
||||||
newCtx, result, abort := app.anteHandler(ctx, tx)
|
newCtx, result, abort := app.anteHandler(ctx, tx)
|
||||||
|
@ -418,7 +519,7 @@ func (app *BaseApp) runTx(isCheckTx bool, txBytes []byte, tx sdk.Tx) (result sdk
|
||||||
|
|
||||||
// Get the correct cache
|
// Get the correct cache
|
||||||
var msCache sdk.CacheMultiStore
|
var msCache sdk.CacheMultiStore
|
||||||
if isCheckTx == true {
|
if mode == runTxModeCheck || mode == runTxModeSimulate {
|
||||||
// CacheWrap app.checkState.ms in case it fails.
|
// CacheWrap app.checkState.ms in case it fails.
|
||||||
msCache = app.checkState.CacheMultiStore()
|
msCache = app.checkState.CacheMultiStore()
|
||||||
ctx = ctx.WithMultiStore(msCache)
|
ctx = ctx.WithMultiStore(msCache)
|
||||||
|
@ -426,13 +527,15 @@ func (app *BaseApp) runTx(isCheckTx bool, txBytes []byte, tx sdk.Tx) (result sdk
|
||||||
// CacheWrap app.deliverState.ms in case it fails.
|
// CacheWrap app.deliverState.ms in case it fails.
|
||||||
msCache = app.deliverState.CacheMultiStore()
|
msCache = app.deliverState.CacheMultiStore()
|
||||||
ctx = ctx.WithMultiStore(msCache)
|
ctx = ctx.WithMultiStore(msCache)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = handler(ctx, msg)
|
result = handler(ctx, msg)
|
||||||
|
|
||||||
// If result was successful, write to app.checkState.ms or app.deliverState.ms
|
// Set gas utilized
|
||||||
if result.IsOK() {
|
result.GasUsed = ctx.GasMeter().GasConsumed()
|
||||||
|
|
||||||
|
// If not a simulated run and result was successful, write to app.checkState.ms or app.deliverState.ms
|
||||||
|
if mode != runTxModeSimulate && result.IsOK() {
|
||||||
msCache.Write()
|
msCache.Write()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
abci "github.com/tendermint/abci/types"
|
abci "github.com/tendermint/abci/types"
|
||||||
"github.com/tendermint/go-crypto"
|
"github.com/tendermint/go-crypto"
|
||||||
|
@ -16,6 +17,7 @@ import (
|
||||||
"github.com/tendermint/tmlibs/log"
|
"github.com/tendermint/tmlibs/log"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/wire"
|
||||||
)
|
)
|
||||||
|
|
||||||
func defaultLogger() log.Logger {
|
func defaultLogger() log.Logger {
|
||||||
|
@ -25,7 +27,9 @@ func defaultLogger() log.Logger {
|
||||||
func newBaseApp(name string) *BaseApp {
|
func newBaseApp(name string) *BaseApp {
|
||||||
logger := defaultLogger()
|
logger := defaultLogger()
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
return NewBaseApp(name, nil, logger, db)
|
codec := wire.NewCodec()
|
||||||
|
wire.RegisterCrypto(codec)
|
||||||
|
return NewBaseApp(name, codec, logger, db)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMountStores(t *testing.T) {
|
func TestMountStores(t *testing.T) {
|
||||||
|
@ -167,7 +171,7 @@ func TestInitChainer(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
query := abci.RequestQuery{
|
query := abci.RequestQuery{
|
||||||
Path: "/main/key",
|
Path: "/store/main/key",
|
||||||
Data: key,
|
Data: key,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,6 +264,97 @@ func TestDeliverTx(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSimulateTx(t *testing.T) {
|
||||||
|
app := newBaseApp(t.Name())
|
||||||
|
|
||||||
|
// make a cap key and mount the store
|
||||||
|
capKey := sdk.NewKVStoreKey("main")
|
||||||
|
app.MountStoresIAVL(capKey)
|
||||||
|
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
counter := 0
|
||||||
|
app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) { return })
|
||||||
|
app.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
|
ctx.GasMeter().ConsumeGas(10, "test")
|
||||||
|
store := ctx.KVStore(capKey)
|
||||||
|
// ensure store is never written
|
||||||
|
require.Nil(t, store.Get([]byte("key")))
|
||||||
|
store.Set([]byte("key"), []byte("value"))
|
||||||
|
// check we can see the current header
|
||||||
|
thisHeader := ctx.BlockHeader()
|
||||||
|
height := int64(counter)
|
||||||
|
assert.Equal(t, height, thisHeader.Height)
|
||||||
|
counter++
|
||||||
|
return sdk.Result{}
|
||||||
|
})
|
||||||
|
|
||||||
|
tx := testUpdatePowerTx{} // doesn't matter
|
||||||
|
header := abci.Header{AppHash: []byte("apphash")}
|
||||||
|
|
||||||
|
app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) {
|
||||||
|
var ttx testUpdatePowerTx
|
||||||
|
fromJSON(txBytes, &ttx)
|
||||||
|
return ttx, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
nBlocks := 3
|
||||||
|
for blockN := 0; blockN < nBlocks; blockN++ {
|
||||||
|
// block1
|
||||||
|
header.Height = int64(blockN + 1)
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
result := app.Simulate(tx)
|
||||||
|
require.Equal(t, result.Code, sdk.ABCICodeOK)
|
||||||
|
require.Equal(t, int64(80), result.GasUsed)
|
||||||
|
counter--
|
||||||
|
encoded, err := json.Marshal(tx)
|
||||||
|
require.Nil(t, err)
|
||||||
|
query := abci.RequestQuery{
|
||||||
|
Path: "/app/simulate",
|
||||||
|
Data: encoded,
|
||||||
|
}
|
||||||
|
queryResult := app.Query(query)
|
||||||
|
require.Equal(t, queryResult.Code, uint32(sdk.ABCICodeOK))
|
||||||
|
var res sdk.Result
|
||||||
|
app.cdc.MustUnmarshalBinary(queryResult.Value, &res)
|
||||||
|
require.Equal(t, sdk.ABCICodeOK, res.Code)
|
||||||
|
require.Equal(t, int64(160), res.GasUsed)
|
||||||
|
app.EndBlock(abci.RequestEndBlock{})
|
||||||
|
app.Commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that transactions exceeding gas limits fail
|
||||||
|
func TestTxGasLimits(t *testing.T) {
|
||||||
|
logger := defaultLogger()
|
||||||
|
db := dbm.NewMemDB()
|
||||||
|
app := NewBaseApp(t.Name(), nil, logger, db)
|
||||||
|
|
||||||
|
// make a cap key and mount the store
|
||||||
|
capKey := sdk.NewKVStoreKey("main")
|
||||||
|
app.MountStoresIAVL(capKey)
|
||||||
|
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
app.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx) (newCtx sdk.Context, res sdk.Result, abort bool) {
|
||||||
|
newCtx = ctx.WithGasMeter(sdk.NewGasMeter(0))
|
||||||
|
return
|
||||||
|
})
|
||||||
|
app.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
|
ctx.GasMeter().ConsumeGas(10, "counter")
|
||||||
|
return sdk.Result{}
|
||||||
|
})
|
||||||
|
|
||||||
|
tx := testUpdatePowerTx{} // doesn't matter
|
||||||
|
header := abci.Header{AppHash: []byte("apphash")}
|
||||||
|
|
||||||
|
app.BeginBlock(abci.RequestBeginBlock{Header: header})
|
||||||
|
res := app.Deliver(tx)
|
||||||
|
assert.Equal(t, res.Code, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOutOfGas), "Expected transaction to run out of gas")
|
||||||
|
app.EndBlock(abci.RequestEndBlock{})
|
||||||
|
app.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
// Test that we can only query from the latest committed state.
|
// Test that we can only query from the latest committed state.
|
||||||
func TestQuery(t *testing.T) {
|
func TestQuery(t *testing.T) {
|
||||||
app := newBaseApp(t.Name())
|
app := newBaseApp(t.Name())
|
||||||
|
@ -280,7 +375,7 @@ func TestQuery(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
query := abci.RequestQuery{
|
query := abci.RequestQuery{
|
||||||
Path: "/main/key",
|
Path: "/store/main/key",
|
||||||
Data: key,
|
Data: key,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,6 +402,39 @@ func TestQuery(t *testing.T) {
|
||||||
assert.Equal(t, value, res.Value)
|
assert.Equal(t, value, res.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test p2p filter queries
|
||||||
|
func TestP2PQuery(t *testing.T) {
|
||||||
|
app := newBaseApp(t.Name())
|
||||||
|
|
||||||
|
// make a cap key and mount the store
|
||||||
|
capKey := sdk.NewKVStoreKey("main")
|
||||||
|
app.MountStoresIAVL(capKey)
|
||||||
|
err := app.LoadLatestVersion(capKey) // needed to make stores non-nil
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
app.SetAddrPeerFilter(func(addrport string) abci.ResponseQuery {
|
||||||
|
require.Equal(t, "1.1.1.1:8000", addrport)
|
||||||
|
return abci.ResponseQuery{Code: uint32(3)}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.SetPubKeyPeerFilter(func(pubkey string) abci.ResponseQuery {
|
||||||
|
require.Equal(t, "testpubkey", pubkey)
|
||||||
|
return abci.ResponseQuery{Code: uint32(4)}
|
||||||
|
})
|
||||||
|
|
||||||
|
addrQuery := abci.RequestQuery{
|
||||||
|
Path: "/p2p/filter/addr/1.1.1.1:8000",
|
||||||
|
}
|
||||||
|
res := app.Query(addrQuery)
|
||||||
|
require.Equal(t, uint32(3), res.Code)
|
||||||
|
|
||||||
|
pubkeyQuery := abci.RequestQuery{
|
||||||
|
Path: "/p2p/filter/pubkey/testpubkey",
|
||||||
|
}
|
||||||
|
res = app.Query(pubkeyQuery)
|
||||||
|
require.Equal(t, uint32(4), res.Code)
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------
|
//----------------------
|
||||||
// TODO: clean this up
|
// TODO: clean this up
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,7 @@ func (ctx CoreContext) QuerySubspace(cdc *wire.Codec, subspace []byte, storeName
|
||||||
|
|
||||||
// Query from Tendermint with the provided storename and path
|
// Query from Tendermint with the provided storename and path
|
||||||
func (ctx CoreContext) query(key cmn.HexBytes, storeName, endPath string) (res []byte, err error) {
|
func (ctx CoreContext) query(key cmn.HexBytes, storeName, endPath string) (res []byte, err error) {
|
||||||
|
path := fmt.Sprintf("/store/%s/key", storeName)
|
||||||
path := fmt.Sprintf("/%s/%s", storeName, endPath)
|
|
||||||
node, err := ctx.GetNode()
|
node, err := ctx.GetNode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return res, err
|
||||||
|
@ -114,6 +113,7 @@ func (ctx CoreContext) SignAndBuild(name, passphrase string, msg sdk.Msg, cdc *w
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
Sequences: []int64{sequence},
|
Sequences: []int64{sequence},
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
|
Fee: sdk.NewStdFee(10000, sdk.Coin{}), // TODO run simulate to estimate gas?
|
||||||
}
|
}
|
||||||
|
|
||||||
keybase, err := keys.GetKeyBase()
|
keybase, err := keys.GetKeyBase()
|
||||||
|
|
|
@ -40,7 +40,7 @@ var (
|
||||||
manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}}
|
manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}}
|
||||||
fee = sdk.StdFee{
|
fee = sdk.StdFee{
|
||||||
sdk.Coins{{"foocoin", 0}},
|
sdk.Coins{{"foocoin", 0}},
|
||||||
0,
|
100000,
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMsg1 = bank.MsgSend{
|
sendMsg1 = bank.MsgSend{
|
||||||
|
|
|
@ -66,8 +66,9 @@ func GaiaAppInit() server.AppInit {
|
||||||
|
|
||||||
fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError)
|
fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||||
fsAppGenTx.String(flagName, "", "validator moniker, if left blank, do not add validator")
|
fsAppGenTx.String(flagName, "", "validator moniker, if left blank, do not add validator")
|
||||||
fsAppGenTx.String(flagClientHome, DefaultCLIHome, "home directory for the client, used for key generation")
|
fsAppGenTx.String(flagClientHome, DefaultCLIHome,
|
||||||
fsAppGenTx.Bool(flagOWK, false, "overwrite the for the accounts created")
|
"home directory for the client, used for key generation")
|
||||||
|
fsAppGenTx.Bool(flagOWK, false, "overwrite the accounts created")
|
||||||
|
|
||||||
return server.AppInit{
|
return server.AppInit{
|
||||||
FlagsAppGenState: fsAppGenState,
|
FlagsAppGenState: fsAppGenState,
|
||||||
|
|
|
@ -2,8 +2,8 @@ openapi: 3.0.0
|
||||||
servers:
|
servers:
|
||||||
- url: 'http://localhost:8998'
|
- url: 'http://localhost:8998'
|
||||||
info:
|
info:
|
||||||
version: "1.0.0-oas3"
|
version: "1.1.0"
|
||||||
title: Light client daemon to interface with Cosmos baseserver via REST
|
title: Light client daemon to interface with full Gaia node via REST
|
||||||
description: Specification for the LCD provided by `gaia rest-server`
|
description: Specification for the LCD provided by `gaia rest-server`
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
|
@ -13,7 +13,7 @@ paths:
|
||||||
description: Get the version of the LCD running locally to compare against expected
|
description: Get the version of the LCD running locally to compare against expected
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Plaintext version i.e. "v0.5.0"
|
description: Plaintext version i.e. "0.16.0-dev-26440095"
|
||||||
/node_info:
|
/node_info:
|
||||||
description: Only the node info. Block information can be queried via /block/latest
|
description: Only the node info. Block information can be queried via /block/latest
|
||||||
get:
|
get:
|
||||||
|
@ -26,25 +26,31 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
id:
|
||||||
|
description: ???
|
||||||
|
type: string
|
||||||
|
listen_addr:
|
||||||
|
type: string
|
||||||
|
example: 192.168.56.1:46656
|
||||||
|
network:
|
||||||
|
type: string
|
||||||
|
example: gaia-5000
|
||||||
|
version:
|
||||||
|
description: Tendermint version
|
||||||
|
type: string
|
||||||
|
example: 0.19.1
|
||||||
|
channels:
|
||||||
|
description: ???
|
||||||
|
type: string
|
||||||
pub_key:
|
pub_key:
|
||||||
$ref: '#/components/schemas/PubKey'
|
$ref: '#/components/schemas/PubKey'
|
||||||
moniker:
|
moniker:
|
||||||
type: string
|
type: string
|
||||||
example: 159.89.198.221
|
example: 159.89.198.221
|
||||||
network:
|
|
||||||
type: string
|
|
||||||
example: gaia-2
|
|
||||||
remote_addr:
|
remote_addr:
|
||||||
type: string
|
type: string
|
||||||
listen_addr:
|
|
||||||
type: string
|
|
||||||
example: 192.168.56.1:46656
|
|
||||||
version:
|
|
||||||
description: Tendermint version
|
|
||||||
type: string
|
|
||||||
example: 0.15.0
|
|
||||||
other:
|
other:
|
||||||
description: more information on versions
|
description: more information on versions and options for the node
|
||||||
type: array
|
type: array
|
||||||
/syncing:
|
/syncing:
|
||||||
get:
|
get:
|
||||||
|
@ -204,6 +210,10 @@ paths:
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
|
type:
|
||||||
|
description: "???"
|
||||||
|
type: string
|
||||||
|
value:
|
||||||
$ref: "#/components/schemas/Balance"
|
$ref: "#/components/schemas/Balance"
|
||||||
204:
|
204:
|
||||||
description: There is no data for the requested account. This is not a 404 as the account might exist, just does not hold data.
|
description: There is no data for the requested account. This is not a 404 as the account might exist, just does not hold data.
|
||||||
|
@ -226,6 +236,7 @@ paths:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
|
description: Name of locally stored key
|
||||||
type: string
|
type: string
|
||||||
password:
|
password:
|
||||||
type: string
|
type: string
|
||||||
|
@ -234,6 +245,9 @@ paths:
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/Coins"
|
$ref: "#/components/schemas/Coins"
|
||||||
chain_id:
|
chain_id:
|
||||||
|
description: Target chain
|
||||||
|
type: string
|
||||||
|
src_chain_id:
|
||||||
type: string
|
type: string
|
||||||
squence:
|
squence:
|
||||||
type: number
|
type: number
|
||||||
|
@ -242,19 +256,6 @@ paths:
|
||||||
description: Tx was send and will probably be added to the next block
|
description: Tx was send and will probably be added to the next block
|
||||||
400:
|
400:
|
||||||
description: The Tx was malformated
|
description: The Tx was malformated
|
||||||
/accounts/{address}/nonce:
|
|
||||||
parameters:
|
|
||||||
- in: path
|
|
||||||
name: address
|
|
||||||
description: Account address
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/Address"
|
|
||||||
get:
|
|
||||||
summary: Get the nonce for a certain account
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: Plaintext nonce i.e. "4" defaults to "0"
|
|
||||||
/blocks/latest:
|
/blocks/latest:
|
||||||
get:
|
get:
|
||||||
summary: Get the latest block
|
summary: Get the latest block
|
||||||
|
@ -667,15 +668,16 @@ components:
|
||||||
Balance:
|
Balance:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
height:
|
address:
|
||||||
type: number
|
type: string
|
||||||
example: 123456
|
|
||||||
coins:
|
coins:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/Coins"
|
$ref: "#/components/schemas/Coins"
|
||||||
credit:
|
public_key:
|
||||||
type: array
|
$ref: "#/components/schemas/PubKey"
|
||||||
|
sequence:
|
||||||
|
type: number
|
||||||
BlockID:
|
BlockID:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -70,6 +70,7 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
||||||
|
|
||||||
// register message routes
|
// register message routes
|
||||||
app.Router().
|
app.Router().
|
||||||
|
AddRoute("auth", auth.NewHandler(app.accountMapper.(auth.AccountMapper))).
|
||||||
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
|
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
|
||||||
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
|
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
|
||||||
AddRoute("stake", stake.NewHandler(app.stakeKeeper))
|
AddRoute("stake", stake.NewHandler(app.stakeKeeper))
|
||||||
|
|
|
@ -39,7 +39,7 @@ var (
|
||||||
manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}}
|
manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}}
|
||||||
fee = sdk.StdFee{
|
fee = sdk.StdFee{
|
||||||
sdk.Coins{{"foocoin", 0}},
|
sdk.Coins{{"foocoin", 0}},
|
||||||
0,
|
100000,
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMsg1 = bank.MsgSend{
|
sendMsg1 = bank.MsgSend{
|
||||||
|
@ -208,6 +208,61 @@ func TestGenesis(t *testing.T) {
|
||||||
assert.Equal(t, acc, res1)
|
assert.Equal(t, acc, res1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMsgChangePubKey(t *testing.T) {
|
||||||
|
|
||||||
|
bapp := newBasecoinApp()
|
||||||
|
|
||||||
|
// Construct some genesis bytes to reflect basecoin/types/AppAccount
|
||||||
|
// Give 77 foocoin to the first key
|
||||||
|
coins, err := sdk.ParseCoins("77foocoin")
|
||||||
|
require.Nil(t, err)
|
||||||
|
baseAcc := auth.BaseAccount{
|
||||||
|
Address: addr1,
|
||||||
|
Coins: coins,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct genesis state
|
||||||
|
err = setGenesisAccounts(bapp, baseAcc)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
// A checkTx context (true)
|
||||||
|
ctxCheck := bapp.BaseApp.NewContext(true, abci.Header{})
|
||||||
|
res1 := bapp.accountMapper.GetAccount(ctxCheck, addr1)
|
||||||
|
assert.Equal(t, baseAcc, res1.(*types.AppAccount).BaseAccount)
|
||||||
|
|
||||||
|
// Run a CheckDeliver
|
||||||
|
SignCheckDeliver(t, bapp, sendMsg1, []int64{0}, true, priv1)
|
||||||
|
|
||||||
|
// Check balances
|
||||||
|
CheckBalance(t, bapp, addr1, "67foocoin")
|
||||||
|
CheckBalance(t, bapp, addr2, "10foocoin")
|
||||||
|
|
||||||
|
changePubKeyMsg := auth.MsgChangeKey{
|
||||||
|
Address: addr1,
|
||||||
|
NewPubKey: priv2.PubKey(),
|
||||||
|
}
|
||||||
|
|
||||||
|
ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{})
|
||||||
|
acc := bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
||||||
|
|
||||||
|
// send a MsgChangePubKey
|
||||||
|
SignCheckDeliver(t, bapp, changePubKeyMsg, []int64{1}, true, priv1)
|
||||||
|
acc = bapp.accountMapper.GetAccount(ctxDeliver, addr1)
|
||||||
|
|
||||||
|
assert.True(t, priv2.PubKey().Equals(acc.GetPubKey()))
|
||||||
|
|
||||||
|
// signing a SendMsg with the old privKey should be an auth error
|
||||||
|
tx := genTx(sendMsg1, []int64{2}, priv1)
|
||||||
|
res := bapp.Deliver(tx)
|
||||||
|
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
|
||||||
|
|
||||||
|
// resigning the tx with the new correct priv key should work
|
||||||
|
SignCheckDeliver(t, bapp, sendMsg1, []int64{2}, true, priv2)
|
||||||
|
|
||||||
|
// Check balances
|
||||||
|
CheckBalance(t, bapp, addr1, "57foocoin")
|
||||||
|
CheckBalance(t, bapp, addr2, "20foocoin")
|
||||||
|
}
|
||||||
|
|
||||||
func TestMsgSendWithAccounts(t *testing.T) {
|
func TestMsgSendWithAccounts(t *testing.T) {
|
||||||
bapp := newBasecoinApp()
|
bapp := newBasecoinApp()
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ var (
|
||||||
coins = sdk.Coins{{"foocoin", 10}}
|
coins = sdk.Coins{{"foocoin", 10}}
|
||||||
fee = sdk.StdFee{
|
fee = sdk.StdFee{
|
||||||
sdk.Coins{{"foocoin", 0}},
|
sdk.Coins{{"foocoin", 0}},
|
||||||
0,
|
1000000,
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMsg = bank.MsgSend{
|
sendMsg = bank.MsgSend{
|
||||||
|
|
|
@ -31,10 +31,9 @@ func TestInitApp(t *testing.T) {
|
||||||
app.InitChain(req)
|
app.InitChain(req)
|
||||||
app.Commit()
|
app.Commit()
|
||||||
|
|
||||||
// XXX test failing
|
|
||||||
// make sure we can query these values
|
// make sure we can query these values
|
||||||
query := abci.RequestQuery{
|
query := abci.RequestQuery{
|
||||||
Path: "/main/key",
|
Path: "/store/main/key",
|
||||||
Data: []byte("foo"),
|
Data: []byte("foo"),
|
||||||
}
|
}
|
||||||
qres := app.Query(query)
|
qres := app.Query(query)
|
||||||
|
@ -70,7 +69,7 @@ func TestDeliverTx(t *testing.T) {
|
||||||
|
|
||||||
// make sure we can query these values
|
// make sure we can query these values
|
||||||
query := abci.RequestQuery{
|
query := abci.RequestQuery{
|
||||||
Path: "/main/key",
|
Path: "/store/main/key",
|
||||||
Data: []byte(key),
|
Data: []byte(key),
|
||||||
}
|
}
|
||||||
qres := app.Query(query)
|
qres := app.Query(query)
|
||||||
|
|
|
@ -50,6 +50,10 @@ func (ms multiStore) GetKVStore(key sdk.StoreKey) sdk.KVStore {
|
||||||
return ms.kv[key]
|
return ms.kv[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ms multiStore) GetKVStoreWithGas(meter sdk.GasMeter, key sdk.StoreKey) sdk.KVStore {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
func (ms multiStore) GetStore(key sdk.StoreKey) sdk.Store {
|
func (ms multiStore) GetStore(key sdk.StoreKey) sdk.Store {
|
||||||
panic("not implemented")
|
panic("not implemented")
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -210,16 +211,18 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
|
||||||
func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) (
|
func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) (
|
||||||
validators []tmtypes.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) {
|
validators []tmtypes.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) {
|
||||||
|
|
||||||
// XXX sort the files by contents just incase people renamed their files
|
|
||||||
var fos []os.FileInfo
|
var fos []os.FileInfo
|
||||||
fos, err = ioutil.ReadDir(genTxsDir)
|
fos, err = ioutil.ReadDir(genTxsDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
genTxs := make(map[string]GenesisTx)
|
||||||
|
var nodeIDs []string
|
||||||
for _, fo := range fos {
|
for _, fo := range fos {
|
||||||
filename := path.Join(genTxsDir, fo.Name())
|
filename := path.Join(genTxsDir, fo.Name())
|
||||||
if !fo.IsDir() && (path.Ext(filename) != ".json") {
|
if !fo.IsDir() && (path.Ext(filename) != ".json") {
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the genTx
|
// get the genTx
|
||||||
|
@ -234,6 +237,15 @@ func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) (
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
genTxs[genTx.NodeID] = genTx
|
||||||
|
nodeIDs = append(nodeIDs, genTx.NodeID)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(nodeIDs)
|
||||||
|
|
||||||
|
for _, nodeID := range nodeIDs {
|
||||||
|
genTx := genTxs[nodeID]
|
||||||
|
|
||||||
// combine some stuff
|
// combine some stuff
|
||||||
validators = append(validators, genTx.Validator)
|
validators = append(validators, genTx.Validator)
|
||||||
appGenTxs = append(appGenTxs, genTx.AppGenTx)
|
appGenTxs = append(appGenTxs, genTx.AppGenTx)
|
||||||
|
|
|
@ -79,7 +79,6 @@ func AddCommands(
|
||||||
ShowNodeIDCmd(ctx),
|
ShowNodeIDCmd(ctx),
|
||||||
ShowValidatorCmd(ctx),
|
ShowValidatorCmd(ctx),
|
||||||
ExportCmd(ctx, cdc, appExport),
|
ExportCmd(ctx, cdc, appExport),
|
||||||
UnsafeResetAllCmd(ctx),
|
|
||||||
version.VersionCmd,
|
version.VersionCmd,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,3 +72,8 @@ func (cms cacheMultiStore) GetStore(key StoreKey) Store {
|
||||||
func (cms cacheMultiStore) GetKVStore(key StoreKey) KVStore {
|
func (cms cacheMultiStore) GetKVStore(key StoreKey) KVStore {
|
||||||
return cms.stores[key].(KVStore)
|
return cms.stores[key].(KVStore)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements MultiStore.
|
||||||
|
func (cms cacheMultiStore) GetKVStoreWithGas(meter sdk.GasMeter, key StoreKey) KVStore {
|
||||||
|
return NewGasKVStore(meter, cms.GetKVStore(key))
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nolint
|
||||||
|
const (
|
||||||
|
HasCost = 10
|
||||||
|
ReadCostFlat = 10
|
||||||
|
ReadCostPerByte = 1
|
||||||
|
WriteCostFlat = 10
|
||||||
|
WriteCostPerByte = 10
|
||||||
|
KeyCostFlat = 5
|
||||||
|
ValueCostFlat = 10
|
||||||
|
ValueCostPerByte = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// gasKVStore applies gas tracking to an underlying kvstore
|
||||||
|
type gasKVStore struct {
|
||||||
|
gasMeter sdk.GasMeter
|
||||||
|
parent sdk.KVStore
|
||||||
|
}
|
||||||
|
|
||||||
|
// nolint
|
||||||
|
func NewGasKVStore(gasMeter sdk.GasMeter, parent sdk.KVStore) *gasKVStore {
|
||||||
|
kvs := &gasKVStore{
|
||||||
|
gasMeter: gasMeter,
|
||||||
|
parent: parent,
|
||||||
|
}
|
||||||
|
return kvs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Store.
|
||||||
|
func (gi *gasKVStore) GetStoreType() sdk.StoreType {
|
||||||
|
return gi.parent.GetStoreType()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements KVStore.
|
||||||
|
func (gi *gasKVStore) Get(key []byte) (value []byte) {
|
||||||
|
gi.gasMeter.ConsumeGas(ReadCostFlat, "GetFlat")
|
||||||
|
value = gi.parent.Get(key)
|
||||||
|
// TODO overflow-safe math?
|
||||||
|
gi.gasMeter.ConsumeGas(ReadCostPerByte*sdk.Gas(len(value)), "ReadPerByte")
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements KVStore.
|
||||||
|
func (gi *gasKVStore) Set(key []byte, value []byte) {
|
||||||
|
gi.gasMeter.ConsumeGas(WriteCostFlat, "SetFlat")
|
||||||
|
// TODO overflow-safe math?
|
||||||
|
gi.gasMeter.ConsumeGas(WriteCostPerByte*sdk.Gas(len(value)), "SetPerByte")
|
||||||
|
gi.parent.Set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements KVStore.
|
||||||
|
func (gi *gasKVStore) Has(key []byte) bool {
|
||||||
|
gi.gasMeter.ConsumeGas(HasCost, "Has")
|
||||||
|
return gi.parent.Has(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements KVStore.
|
||||||
|
func (gi *gasKVStore) Delete(key []byte) {
|
||||||
|
// No gas costs for deletion
|
||||||
|
gi.parent.Delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements KVStore.
|
||||||
|
func (gi *gasKVStore) Iterator(start, end []byte) sdk.Iterator {
|
||||||
|
return gi.iterator(start, end, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements KVStore.
|
||||||
|
func (gi *gasKVStore) ReverseIterator(start, end []byte) sdk.Iterator {
|
||||||
|
return gi.iterator(start, end, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements KVStore.
|
||||||
|
func (gi *gasKVStore) SubspaceIterator(prefix []byte) sdk.Iterator {
|
||||||
|
return gi.iterator(prefix, sdk.PrefixEndBytes(prefix), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements KVStore.
|
||||||
|
func (gi *gasKVStore) ReverseSubspaceIterator(prefix []byte) sdk.Iterator {
|
||||||
|
return gi.iterator(prefix, sdk.PrefixEndBytes(prefix), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements KVStore.
|
||||||
|
func (gi *gasKVStore) CacheWrap() sdk.CacheWrap {
|
||||||
|
panic("you cannot CacheWrap a GasKVStore")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gi *gasKVStore) iterator(start, end []byte, ascending bool) sdk.Iterator {
|
||||||
|
var parent sdk.Iterator
|
||||||
|
if ascending {
|
||||||
|
parent = gi.parent.Iterator(start, end)
|
||||||
|
} else {
|
||||||
|
parent = gi.parent.ReverseIterator(start, end)
|
||||||
|
}
|
||||||
|
return newGasIterator(gi.gasMeter, parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
type gasIterator struct {
|
||||||
|
gasMeter sdk.GasMeter
|
||||||
|
parent sdk.Iterator
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGasIterator(gasMeter sdk.GasMeter, parent sdk.Iterator) sdk.Iterator {
|
||||||
|
return &gasIterator{
|
||||||
|
gasMeter: gasMeter,
|
||||||
|
parent: parent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Iterator.
|
||||||
|
func (g *gasIterator) Domain() (start []byte, end []byte) {
|
||||||
|
return g.parent.Domain()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Iterator.
|
||||||
|
func (g *gasIterator) Valid() bool {
|
||||||
|
return g.parent.Valid()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Iterator.
|
||||||
|
func (g *gasIterator) Next() {
|
||||||
|
g.parent.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Iterator.
|
||||||
|
func (g *gasIterator) Key() (key []byte) {
|
||||||
|
g.gasMeter.ConsumeGas(KeyCostFlat, "KeyFlat")
|
||||||
|
key = g.parent.Key()
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Iterator.
|
||||||
|
func (g *gasIterator) Value() (value []byte) {
|
||||||
|
value = g.parent.Value()
|
||||||
|
g.gasMeter.ConsumeGas(ValueCostFlat, "ValueFlat")
|
||||||
|
g.gasMeter.ConsumeGas(ValueCostPerByte*sdk.Gas(len(value)), "ValuePerByte")
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Iterator.
|
||||||
|
func (g *gasIterator) Close() {
|
||||||
|
g.parent.Close()
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
dbm "github.com/tendermint/tmlibs/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newGasKVStore() KVStore {
|
||||||
|
meter := sdk.NewGasMeter(1000)
|
||||||
|
mem := dbStoreAdapter{dbm.NewMemDB()}
|
||||||
|
return NewGasKVStore(meter, mem)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGasKVStoreBasic(t *testing.T) {
|
||||||
|
mem := dbStoreAdapter{dbm.NewMemDB()}
|
||||||
|
meter := sdk.NewGasMeter(1000)
|
||||||
|
st := NewGasKVStore(meter, mem)
|
||||||
|
require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
|
||||||
|
st.Set(keyFmt(1), valFmt(1))
|
||||||
|
require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
|
||||||
|
st.Delete(keyFmt(1))
|
||||||
|
require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
|
||||||
|
require.Equal(t, meter.GasConsumed(), sdk.Gas(183))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGasKVStoreIterator(t *testing.T) {
|
||||||
|
mem := dbStoreAdapter{dbm.NewMemDB()}
|
||||||
|
meter := sdk.NewGasMeter(1000)
|
||||||
|
st := NewGasKVStore(meter, mem)
|
||||||
|
require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
|
||||||
|
require.Empty(t, st.Get(keyFmt(2)), "Expected `key2` to be empty")
|
||||||
|
st.Set(keyFmt(1), valFmt(1))
|
||||||
|
st.Set(keyFmt(2), valFmt(2))
|
||||||
|
iterator := st.Iterator(nil, nil)
|
||||||
|
ka := iterator.Key()
|
||||||
|
require.Equal(t, ka, keyFmt(1))
|
||||||
|
va := iterator.Value()
|
||||||
|
require.Equal(t, va, valFmt(1))
|
||||||
|
iterator.Next()
|
||||||
|
kb := iterator.Key()
|
||||||
|
require.Equal(t, kb, keyFmt(2))
|
||||||
|
vb := iterator.Value()
|
||||||
|
require.Equal(t, vb, valFmt(2))
|
||||||
|
iterator.Next()
|
||||||
|
require.False(t, iterator.Valid())
|
||||||
|
require.Panics(t, iterator.Next)
|
||||||
|
require.Equal(t, meter.GasConsumed(), sdk.Gas(356))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGasKVStoreOutOfGasSet(t *testing.T) {
|
||||||
|
mem := dbStoreAdapter{dbm.NewMemDB()}
|
||||||
|
meter := sdk.NewGasMeter(0)
|
||||||
|
st := NewGasKVStore(meter, mem)
|
||||||
|
require.Panics(t, func() { st.Set(keyFmt(1), valFmt(1)) }, "Expected out-of-gas")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGasKVStoreOutOfGasIterator(t *testing.T) {
|
||||||
|
mem := dbStoreAdapter{dbm.NewMemDB()}
|
||||||
|
meter := sdk.NewGasMeter(200)
|
||||||
|
st := NewGasKVStore(meter, mem)
|
||||||
|
st.Set(keyFmt(1), valFmt(1))
|
||||||
|
iterator := st.Iterator(nil, nil)
|
||||||
|
iterator.Next()
|
||||||
|
require.Panics(t, func() { iterator.Value() }, "Expected out-of-gas")
|
||||||
|
}
|
|
@ -183,6 +183,11 @@ func (rs *rootMultiStore) GetKVStore(key StoreKey) KVStore {
|
||||||
return rs.stores[key].(KVStore)
|
return rs.stores[key].(KVStore)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements MultiStore.
|
||||||
|
func (rs *rootMultiStore) GetKVStoreWithGas(meter sdk.GasMeter, key StoreKey) KVStore {
|
||||||
|
return NewGasKVStore(meter, rs.GetKVStore(key))
|
||||||
|
}
|
||||||
|
|
||||||
// getStoreByName will first convert the original name to
|
// getStoreByName will first convert the original name to
|
||||||
// a special key, before looking up the CommitStore.
|
// a special key, before looking up the CommitStore.
|
||||||
// This is not exposed to the extensions (which will need the
|
// This is not exposed to the extensions (which will need the
|
||||||
|
|
|
@ -10,3 +10,6 @@ type BeginBlocker func(ctx Context, req abci.RequestBeginBlock) abci.ResponseBeg
|
||||||
|
|
||||||
// run code after the transactions in a block and return updates to the validator set
|
// run code after the transactions in a block and return updates to the validator set
|
||||||
type EndBlocker func(ctx Context, req abci.RequestEndBlock) abci.ResponseEndBlock
|
type EndBlocker func(ctx Context, req abci.RequestEndBlock) abci.ResponseEndBlock
|
||||||
|
|
||||||
|
// respond to p2p filtering queries from Tendermint
|
||||||
|
type PeerFilter func(info string) abci.ResponseQuery
|
||||||
|
|
|
@ -43,6 +43,7 @@ func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byt
|
||||||
c = c.WithIsCheckTx(isCheckTx)
|
c = c.WithIsCheckTx(isCheckTx)
|
||||||
c = c.WithTxBytes(txBytes)
|
c = c.WithTxBytes(txBytes)
|
||||||
c = c.WithLogger(logger)
|
c = c.WithLogger(logger)
|
||||||
|
c = c.WithGasMeter(NewInfiniteGasMeter())
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ func (c Context) Value(key interface{}) interface{} {
|
||||||
|
|
||||||
// KVStore fetches a KVStore from the MultiStore.
|
// KVStore fetches a KVStore from the MultiStore.
|
||||||
func (c Context) KVStore(key StoreKey) KVStore {
|
func (c Context) KVStore(key StoreKey) KVStore {
|
||||||
return c.multiStore().GetKVStore(key)
|
return c.multiStore().GetKVStoreWithGas(c.GasMeter(), key)
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
|
@ -127,6 +128,7 @@ const (
|
||||||
contextKeyIsCheckTx
|
contextKeyIsCheckTx
|
||||||
contextKeyTxBytes
|
contextKeyTxBytes
|
||||||
contextKeyLogger
|
contextKeyLogger
|
||||||
|
contextKeyGasMeter
|
||||||
)
|
)
|
||||||
|
|
||||||
// NOTE: Do not expose MultiStore.
|
// NOTE: Do not expose MultiStore.
|
||||||
|
@ -155,6 +157,9 @@ func (c Context) TxBytes() []byte {
|
||||||
func (c Context) Logger() log.Logger {
|
func (c Context) Logger() log.Logger {
|
||||||
return c.Value(contextKeyLogger).(log.Logger)
|
return c.Value(contextKeyLogger).(log.Logger)
|
||||||
}
|
}
|
||||||
|
func (c Context) GasMeter() GasMeter {
|
||||||
|
return c.Value(contextKeyGasMeter).(GasMeter)
|
||||||
|
}
|
||||||
func (c Context) WithMultiStore(ms MultiStore) Context {
|
func (c Context) WithMultiStore(ms MultiStore) Context {
|
||||||
return c.withValue(contextKeyMultiStore, ms)
|
return c.withValue(contextKeyMultiStore, ms)
|
||||||
}
|
}
|
||||||
|
@ -177,6 +182,9 @@ func (c Context) WithTxBytes(txBytes []byte) Context {
|
||||||
func (c Context) WithLogger(logger log.Logger) Context {
|
func (c Context) WithLogger(logger log.Logger) Context {
|
||||||
return c.withValue(contextKeyLogger, logger)
|
return c.withValue(contextKeyLogger, logger)
|
||||||
}
|
}
|
||||||
|
func (c Context) WithGasMeter(meter GasMeter) Context {
|
||||||
|
return c.withValue(contextKeyGasMeter, meter)
|
||||||
|
}
|
||||||
|
|
||||||
// Cache the multistore and return a new cached context. The cached context is
|
// Cache the multistore and return a new cached context. The cached context is
|
||||||
// written to the context when writeCache is called.
|
// written to the context when writeCache is called.
|
||||||
|
|
|
@ -52,6 +52,7 @@ const (
|
||||||
CodeUnknownAddress CodeType = 9
|
CodeUnknownAddress CodeType = 9
|
||||||
CodeInsufficientCoins CodeType = 10
|
CodeInsufficientCoins CodeType = 10
|
||||||
CodeInvalidCoins CodeType = 11
|
CodeInvalidCoins CodeType = 11
|
||||||
|
CodeOutOfGas CodeType = 12
|
||||||
|
|
||||||
// CodespaceRoot is a codespace for error codes in this file only.
|
// CodespaceRoot is a codespace for error codes in this file only.
|
||||||
// Notice that 0 is an "unset" codespace, which can be overridden with
|
// Notice that 0 is an "unset" codespace, which can be overridden with
|
||||||
|
@ -88,6 +89,8 @@ func CodeToDefaultMsg(code CodeType) string {
|
||||||
return "Insufficient coins"
|
return "Insufficient coins"
|
||||||
case CodeInvalidCoins:
|
case CodeInvalidCoins:
|
||||||
return "Invalid coins"
|
return "Invalid coins"
|
||||||
|
case CodeOutOfGas:
|
||||||
|
return "Out of gas"
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("Unknown code %d", code)
|
return fmt.Sprintf("Unknown code %d", code)
|
||||||
}
|
}
|
||||||
|
@ -131,6 +134,9 @@ func ErrInsufficientCoins(msg string) Error {
|
||||||
func ErrInvalidCoins(msg string) Error {
|
func ErrInvalidCoins(msg string) Error {
|
||||||
return newErrorWithRootCodespace(CodeInvalidCoins, msg)
|
return newErrorWithRootCodespace(CodeInvalidCoins, msg)
|
||||||
}
|
}
|
||||||
|
func ErrOutOfGas(msg string) Error {
|
||||||
|
return newErrorWithRootCodespace(CodeOutOfGas, msg)
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
// Error & sdkError
|
// Error & sdkError
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import ()
|
||||||
|
|
||||||
|
// Gas measured by the SDK
|
||||||
|
type Gas = int64
|
||||||
|
|
||||||
|
// Error thrown when out of gas
|
||||||
|
type ErrorOutOfGas struct {
|
||||||
|
Descriptor string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GasMeter interface to track gas consumption
|
||||||
|
type GasMeter interface {
|
||||||
|
GasConsumed() Gas
|
||||||
|
ConsumeGas(amount Gas, descriptor string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type basicGasMeter struct {
|
||||||
|
limit Gas
|
||||||
|
consumed Gas
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGasMeter(limit Gas) GasMeter {
|
||||||
|
return &basicGasMeter{
|
||||||
|
limit: limit,
|
||||||
|
consumed: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *basicGasMeter) GasConsumed() Gas {
|
||||||
|
return g.consumed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *basicGasMeter) ConsumeGas(amount Gas, descriptor string) {
|
||||||
|
g.consumed += amount
|
||||||
|
if g.consumed > g.limit {
|
||||||
|
panic(ErrorOutOfGas{descriptor})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type infiniteGasMeter struct {
|
||||||
|
consumed Gas
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInfiniteGasMeter() GasMeter {
|
||||||
|
return &infiniteGasMeter{
|
||||||
|
consumed: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *infiniteGasMeter) GasConsumed() Gas {
|
||||||
|
return g.consumed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *infiniteGasMeter) ConsumeGas(amount Gas, descriptor string) {
|
||||||
|
g.consumed += amount
|
||||||
|
}
|
|
@ -49,6 +49,7 @@ type MultiStore interface { //nolint
|
||||||
// Convenience for fetching substores.
|
// Convenience for fetching substores.
|
||||||
GetStore(StoreKey) Store
|
GetStore(StoreKey) Store
|
||||||
GetKVStore(StoreKey) KVStore
|
GetKVStore(StoreKey) KVStore
|
||||||
|
GetKVStoreWithGas(GasMeter, StoreKey) KVStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// From MultiStore.CacheMultiStore()....
|
// From MultiStore.CacheMultiStore()....
|
||||||
|
|
|
@ -77,8 +77,8 @@ func FeePayer(tx Tx) Address {
|
||||||
// gas to be used by the transaction. The ratio yields an effective "gasprice",
|
// gas to be used by the transaction. The ratio yields an effective "gasprice",
|
||||||
// which must be above some miminum to be accepted into the mempool.
|
// which must be above some miminum to be accepted into the mempool.
|
||||||
type StdFee struct {
|
type StdFee struct {
|
||||||
Amount Coins `json"amount"`
|
Amount Coins `json:"amount"`
|
||||||
Gas int64 `json"gas"`
|
Gas int64 `json:"gas"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStdFee(gas int64, amount ...Coin) StdFee {
|
func NewStdFee(gas int64, amount ...Coin) StdFee {
|
||||||
|
|
|
@ -6,10 +6,10 @@ package version
|
||||||
// TODO improve
|
// TODO improve
|
||||||
|
|
||||||
const Maj = "0"
|
const Maj = "0"
|
||||||
const Min = "16"
|
const Min = "18"
|
||||||
const Fix = "0"
|
const Fix = "0"
|
||||||
|
|
||||||
const Version = "0.16.0-dev"
|
const Version = "0.18.0-dev"
|
||||||
|
|
||||||
// GitCommit set by build flags
|
// GitCommit set by build flags
|
||||||
var GitCommit = ""
|
var GitCommit = ""
|
||||||
|
|
|
@ -8,10 +8,14 @@ import (
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
verifyCost = 100
|
||||||
|
)
|
||||||
|
|
||||||
// NewAnteHandler returns an AnteHandler that checks
|
// NewAnteHandler returns an AnteHandler that checks
|
||||||
// and increments sequence numbers, checks signatures,
|
// and increments sequence numbers, checks signatures,
|
||||||
// and deducts fees from the first signer.
|
// and deducts fees from the first signer.
|
||||||
func NewAnteHandler(accountMapper sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHandler {
|
func NewAnteHandler(am sdk.AccountMapper, feeHandler sdk.FeeHandler) sdk.AnteHandler {
|
||||||
return func(
|
return func(
|
||||||
ctx sdk.Context, tx sdk.Tx,
|
ctx sdk.Context, tx sdk.Tx,
|
||||||
) (_ sdk.Context, _ sdk.Result, abort bool) {
|
) (_ sdk.Context, _ sdk.Result, abort bool) {
|
||||||
|
@ -24,7 +28,6 @@ func NewAnteHandler(accountMapper sdk.AccountMapper, feeHandler sdk.FeeHandler)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: can tx just implement message?
|
|
||||||
msg := tx.GetMsg()
|
msg := tx.GetMsg()
|
||||||
|
|
||||||
// TODO: will this always be a stdtx? should that be used in the function signature?
|
// TODO: will this always be a stdtx? should that be used in the function signature?
|
||||||
|
@ -62,7 +65,7 @@ func NewAnteHandler(accountMapper sdk.AccountMapper, feeHandler sdk.FeeHandler)
|
||||||
|
|
||||||
// check signature, return account with incremented nonce
|
// check signature, return account with incremented nonce
|
||||||
signerAcc, res := processSig(
|
signerAcc, res := processSig(
|
||||||
ctx, accountMapper,
|
ctx, am,
|
||||||
signerAddr, sig, signBytes,
|
signerAddr, sig, signBytes,
|
||||||
)
|
)
|
||||||
if !res.IsOK() {
|
if !res.IsOK() {
|
||||||
|
@ -82,13 +85,16 @@ func NewAnteHandler(accountMapper sdk.AccountMapper, feeHandler sdk.FeeHandler)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the account.
|
// Save the account.
|
||||||
accountMapper.SetAccount(ctx, signerAcc)
|
am.SetAccount(ctx, signerAcc)
|
||||||
signerAccs[i] = signerAcc
|
signerAccs[i] = signerAcc
|
||||||
}
|
}
|
||||||
|
|
||||||
// cache the signer accounts in the context
|
// cache the signer accounts in the context
|
||||||
ctx = WithSigners(ctx, signerAccs)
|
ctx = WithSigners(ctx, signerAccs)
|
||||||
|
|
||||||
|
// set the gas meter
|
||||||
|
ctx = ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas))
|
||||||
|
|
||||||
// TODO: tx tags (?)
|
// TODO: tx tags (?)
|
||||||
|
|
||||||
return ctx, sdk.Result{}, false // continue...
|
return ctx, sdk.Result{}, false // continue...
|
||||||
|
@ -135,6 +141,7 @@ func processSig(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check sig.
|
// Check sig.
|
||||||
|
ctx.GasMeter().ConsumeGas(verifyCost, "ante verify")
|
||||||
if !pubKey.VerifyBytes(signBytes, sig.Signature) {
|
if !pubKey.VerifyBytes(signBytes, sig.Signature) {
|
||||||
return nil, sdk.ErrUnauthorized("signature verification failed").Result()
|
return nil, sdk.ErrUnauthorized("signature verification failed").Result()
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,9 +51,6 @@ func (acc BaseAccount) GetPubKey() crypto.PubKey {
|
||||||
|
|
||||||
// Implements sdk.Account.
|
// Implements sdk.Account.
|
||||||
func (acc *BaseAccount) SetPubKey(pubKey crypto.PubKey) error {
|
func (acc *BaseAccount) SetPubKey(pubKey crypto.PubKey) error {
|
||||||
if acc.PubKey != nil {
|
|
||||||
return errors.New("cannot override BaseAccount pubkey")
|
|
||||||
}
|
|
||||||
acc.PubKey = pubKey
|
acc.PubKey = pubKey
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,10 @@ func TestBaseAccountAddressPubKey(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, pub1, acc.GetPubKey())
|
assert.Equal(t, pub1, acc.GetPubKey())
|
||||||
|
|
||||||
// can't override pubkey
|
// can override pubkey
|
||||||
err = acc.SetPubKey(pub2)
|
err = acc.SetPubKey(pub2)
|
||||||
assert.NotNil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, pub1, acc.GetPubKey())
|
assert.Equal(t, pub2, acc.GetPubKey())
|
||||||
|
|
||||||
//------------------------------------
|
//------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewHandler returns a handler for "auth" type messages.
|
||||||
|
func NewHandler(am AccountMapper) sdk.Handler {
|
||||||
|
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case MsgChangeKey:
|
||||||
|
return handleMsgChangeKey(ctx, am, msg)
|
||||||
|
default:
|
||||||
|
errMsg := "Unrecognized auth Msg type: " + reflect.TypeOf(msg).Name()
|
||||||
|
return sdk.ErrUnknownRequest(errMsg).Result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle MsgChangeKey
|
||||||
|
// Should be very expensive, because once this happens, an account is un-prunable
|
||||||
|
func handleMsgChangeKey(ctx sdk.Context, am AccountMapper, msg MsgChangeKey) sdk.Result {
|
||||||
|
|
||||||
|
err := am.setPubKey(ctx, msg.Address, msg.NewPubKey)
|
||||||
|
if err != nil {
|
||||||
|
return err.Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
return sdk.Result{
|
||||||
|
Tags: sdk.NewTags("action", []byte("changePubkey"), "address", msg.Address.Bytes(), "pubkey", msg.NewPubKey.Bytes()),
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,14 +6,15 @@ import (
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ sdk.AccountMapper = (*accountMapper)(nil)
|
var _ sdk.AccountMapper = (*AccountMapper)(nil)
|
||||||
|
|
||||||
// Implements sdk.AccountMapper.
|
// Implements sdk.AccountMapper.
|
||||||
// This AccountMapper encodes/decodes accounts using the
|
// This AccountMapper encodes/decodes accounts using the
|
||||||
// go-amino (binary) encoding/decoding library.
|
// go-amino (binary) encoding/decoding library.
|
||||||
type accountMapper struct {
|
type AccountMapper struct {
|
||||||
|
|
||||||
// The (unexposed) key used to access the store from the Context.
|
// The (unexposed) key used to access the store from the Context.
|
||||||
key sdk.StoreKey
|
key sdk.StoreKey
|
||||||
|
@ -28,23 +29,23 @@ type accountMapper struct {
|
||||||
// NewAccountMapper returns a new sdk.AccountMapper that
|
// NewAccountMapper returns a new sdk.AccountMapper that
|
||||||
// uses go-amino to (binary) encode and decode concrete sdk.Accounts.
|
// uses go-amino to (binary) encode and decode concrete sdk.Accounts.
|
||||||
// nolint
|
// nolint
|
||||||
func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto sdk.Account) accountMapper {
|
func NewAccountMapper(cdc *wire.Codec, key sdk.StoreKey, proto sdk.Account) AccountMapper {
|
||||||
return accountMapper{
|
return AccountMapper{
|
||||||
key: key,
|
key: key,
|
||||||
proto: proto,
|
proto: proto,
|
||||||
cdc: cdc,
|
cdc: cdc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements sdk.AccountMapper.
|
// Implaements sdk.AccountMapper.
|
||||||
func (am accountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.Address) sdk.Account {
|
func (am AccountMapper) NewAccountWithAddress(ctx sdk.Context, addr sdk.Address) sdk.Account {
|
||||||
acc := am.clonePrototype()
|
acc := am.clonePrototype()
|
||||||
acc.SetAddress(addr)
|
acc.SetAddress(addr)
|
||||||
return acc
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements sdk.AccountMapper.
|
// Implements sdk.AccountMapper.
|
||||||
func (am accountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) sdk.Account {
|
func (am AccountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) sdk.Account {
|
||||||
store := ctx.KVStore(am.key)
|
store := ctx.KVStore(am.key)
|
||||||
bz := store.Get(addr)
|
bz := store.Get(addr)
|
||||||
if bz == nil {
|
if bz == nil {
|
||||||
|
@ -55,7 +56,7 @@ func (am accountMapper) GetAccount(ctx sdk.Context, addr sdk.Address) sdk.Accoun
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements sdk.AccountMapper.
|
// Implements sdk.AccountMapper.
|
||||||
func (am accountMapper) SetAccount(ctx sdk.Context, acc sdk.Account) {
|
func (am AccountMapper) SetAccount(ctx sdk.Context, acc sdk.Account) {
|
||||||
addr := acc.GetAddress()
|
addr := acc.GetAddress()
|
||||||
store := ctx.KVStore(am.key)
|
store := ctx.KVStore(am.key)
|
||||||
bz := am.encodeAccount(acc)
|
bz := am.encodeAccount(acc)
|
||||||
|
@ -63,7 +64,7 @@ func (am accountMapper) SetAccount(ctx sdk.Context, acc sdk.Account) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements sdk.AccountMapper.
|
// Implements sdk.AccountMapper.
|
||||||
func (am accountMapper) IterateAccounts(ctx sdk.Context, process func(sdk.Account) (stop bool)) {
|
func (am AccountMapper) IterateAccounts(ctx sdk.Context, process func(sdk.Account) (stop bool)) {
|
||||||
store := ctx.KVStore(am.key)
|
store := ctx.KVStore(am.key)
|
||||||
iter := store.Iterator(nil, nil)
|
iter := store.Iterator(nil, nil)
|
||||||
for {
|
for {
|
||||||
|
@ -79,11 +80,49 @@ func (am accountMapper) IterateAccounts(ctx sdk.Context, process func(sdk.Accoun
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the PubKey of the account at address
|
||||||
|
func (am AccountMapper) GetPubKey(ctx sdk.Context, addr sdk.Address) (crypto.PubKey, sdk.Error) {
|
||||||
|
acc := am.GetAccount(ctx, addr)
|
||||||
|
if acc == nil {
|
||||||
|
return nil, sdk.ErrUnknownAddress(addr.String())
|
||||||
|
}
|
||||||
|
return acc.GetPubKey(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am AccountMapper) setPubKey(ctx sdk.Context, addr sdk.Address, newPubKey crypto.PubKey) sdk.Error {
|
||||||
|
acc := am.GetAccount(ctx, addr)
|
||||||
|
if acc == nil {
|
||||||
|
return sdk.ErrUnknownAddress(addr.String())
|
||||||
|
}
|
||||||
|
acc.SetPubKey(newPubKey)
|
||||||
|
am.SetAccount(ctx, acc)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the Sequence of the account at address
|
||||||
|
func (am AccountMapper) GetSequence(ctx sdk.Context, addr sdk.Address) (int64, sdk.Error) {
|
||||||
|
acc := am.GetAccount(ctx, addr)
|
||||||
|
if acc == nil {
|
||||||
|
return 0, sdk.ErrUnknownAddress(addr.String())
|
||||||
|
}
|
||||||
|
return acc.GetSequence(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am AccountMapper) setSequence(ctx sdk.Context, addr sdk.Address, newSequence int64) sdk.Error {
|
||||||
|
acc := am.GetAccount(ctx, addr)
|
||||||
|
if acc == nil {
|
||||||
|
return sdk.ErrUnknownAddress(addr.String())
|
||||||
|
}
|
||||||
|
acc.SetSequence(newSequence)
|
||||||
|
am.SetAccount(ctx, acc)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
// misc.
|
// misc.
|
||||||
|
|
||||||
// Creates a new struct (or pointer to struct) from am.proto.
|
// Creates a new struct (or pointer to struct) from am.proto.
|
||||||
func (am accountMapper) clonePrototype() sdk.Account {
|
func (am AccountMapper) clonePrototype() sdk.Account {
|
||||||
protoRt := reflect.TypeOf(am.proto)
|
protoRt := reflect.TypeOf(am.proto)
|
||||||
if protoRt.Kind() == reflect.Ptr {
|
if protoRt.Kind() == reflect.Ptr {
|
||||||
protoCrt := protoRt.Elem()
|
protoCrt := protoRt.Elem()
|
||||||
|
@ -106,7 +145,7 @@ func (am accountMapper) clonePrototype() sdk.Account {
|
||||||
return clone
|
return clone
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am accountMapper) encodeAccount(acc sdk.Account) []byte {
|
func (am AccountMapper) encodeAccount(acc sdk.Account) []byte {
|
||||||
bz, err := am.cdc.MarshalBinaryBare(acc)
|
bz, err := am.cdc.MarshalBinaryBare(acc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -114,7 +153,7 @@ func (am accountMapper) encodeAccount(acc sdk.Account) []byte {
|
||||||
return bz
|
return bz
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am accountMapper) decodeAccount(bz []byte) (acc sdk.Account) {
|
func (am AccountMapper) decodeAccount(bz []byte) (acc sdk.Account) {
|
||||||
err := am.cdc.UnmarshalBinaryBare(bz, &acc)
|
err := am.cdc.UnmarshalBinaryBare(bz, &acc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/tendermint/go-crypto"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MsgChangeKey - high level transaction of the auth module
|
||||||
|
type MsgChangeKey struct {
|
||||||
|
Address sdk.Address `json:"address"`
|
||||||
|
NewPubKey crypto.PubKey `json:"public_key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ sdk.Msg = MsgChangeKey{}
|
||||||
|
|
||||||
|
// NewMsgChangeKey - msg to claim an account and set the PubKey
|
||||||
|
func NewMsgChangeKey(addr sdk.Address, pubkey crypto.PubKey) MsgChangeKey {
|
||||||
|
return MsgChangeKey{Address: addr, NewPubKey: pubkey}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Msg.
|
||||||
|
func (msg MsgChangeKey) Type() string { return "auth" }
|
||||||
|
|
||||||
|
// Implements Msg.
|
||||||
|
func (msg MsgChangeKey) ValidateBasic() sdk.Error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Msg.
|
||||||
|
func (msg MsgChangeKey) GetSignBytes() []byte {
|
||||||
|
b, err := json.Marshal(msg) // XXX: ensure some canonical form
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Msg.
|
||||||
|
func (msg MsgChangeKey) GetSigners() []sdk.Address {
|
||||||
|
return []sdk.Address{msg.Address}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
crypto "github.com/tendermint/go-crypto"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewMsgChangeKey(t *testing.T) {}
|
||||||
|
|
||||||
|
func TestMsgChangeKeyType(t *testing.T) {
|
||||||
|
addr1 := sdk.Address([]byte("input"))
|
||||||
|
newPubKey := crypto.GenPrivKeyEd25519().PubKey()
|
||||||
|
|
||||||
|
var msg = MsgChangeKey{
|
||||||
|
Address: addr1,
|
||||||
|
NewPubKey: newPubKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, msg.Type(), "auth")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMsgChangeKeyValidation(t *testing.T) {
|
||||||
|
|
||||||
|
addr1 := sdk.Address([]byte("input"))
|
||||||
|
|
||||||
|
// emptyPubKey := crypto.PubKeyEd25519{}
|
||||||
|
// var msg = MsgChangeKey{
|
||||||
|
// Address: addr1,
|
||||||
|
// NewPubKey: emptyPubKey,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // fmt.Println(msg.NewPubKey.Empty())
|
||||||
|
// fmt.Println(msg.NewPubKey.Bytes())
|
||||||
|
|
||||||
|
// assert.NotNil(t, msg.ValidateBasic())
|
||||||
|
|
||||||
|
newPubKey := crypto.GenPrivKeyEd25519().PubKey()
|
||||||
|
msg := MsgChangeKey{
|
||||||
|
Address: addr1,
|
||||||
|
NewPubKey: newPubKey,
|
||||||
|
}
|
||||||
|
assert.Nil(t, msg.ValidateBasic())
|
||||||
|
}
|
|
@ -6,6 +6,14 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
costGetCoins sdk.Gas = 10
|
||||||
|
costHasCoins sdk.Gas = 10
|
||||||
|
costSetCoins sdk.Gas = 100
|
||||||
|
costSubtractCoins sdk.Gas = 10
|
||||||
|
costAddCoins sdk.Gas = 10
|
||||||
|
)
|
||||||
|
|
||||||
// Keeper manages transfers between accounts
|
// Keeper manages transfers between accounts
|
||||||
type Keeper struct {
|
type Keeper struct {
|
||||||
am sdk.AccountMapper
|
am sdk.AccountMapper
|
||||||
|
@ -108,6 +116,7 @@ func (keeper ViewKeeper) HasCoins(ctx sdk.Context, addr sdk.Address, amt sdk.Coi
|
||||||
//______________________________________________________________________________________________
|
//______________________________________________________________________________________________
|
||||||
|
|
||||||
func getCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address) sdk.Coins {
|
func getCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address) sdk.Coins {
|
||||||
|
ctx.GasMeter().ConsumeGas(costGetCoins, "getCoins")
|
||||||
acc := am.GetAccount(ctx, addr)
|
acc := am.GetAccount(ctx, addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
return sdk.Coins{}
|
return sdk.Coins{}
|
||||||
|
@ -116,6 +125,7 @@ func getCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address) sdk.Coins
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) sdk.Error {
|
func setCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) sdk.Error {
|
||||||
|
ctx.GasMeter().ConsumeGas(costSetCoins, "setCoins")
|
||||||
acc := am.GetAccount(ctx, addr)
|
acc := am.GetAccount(ctx, addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
acc = am.NewAccountWithAddress(ctx, addr)
|
acc = am.NewAccountWithAddress(ctx, addr)
|
||||||
|
@ -127,11 +137,13 @@ func setCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.C
|
||||||
|
|
||||||
// HasCoins returns whether or not an account has at least amt coins.
|
// HasCoins returns whether or not an account has at least amt coins.
|
||||||
func hasCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) bool {
|
func hasCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) bool {
|
||||||
|
ctx.GasMeter().ConsumeGas(costHasCoins, "hasCoins")
|
||||||
return getCoins(ctx, am, addr).IsGTE(amt)
|
return getCoins(ctx, am, addr).IsGTE(amt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubtractCoins subtracts amt from the coins at the addr.
|
// SubtractCoins subtracts amt from the coins at the addr.
|
||||||
func subtractCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) {
|
func subtractCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) {
|
||||||
|
ctx.GasMeter().ConsumeGas(costSubtractCoins, "subtractCoins")
|
||||||
oldCoins := getCoins(ctx, am, addr)
|
oldCoins := getCoins(ctx, am, addr)
|
||||||
newCoins := oldCoins.Minus(amt)
|
newCoins := oldCoins.Minus(amt)
|
||||||
if !newCoins.IsNotNegative() {
|
if !newCoins.IsNotNegative() {
|
||||||
|
@ -144,6 +156,7 @@ func subtractCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt
|
||||||
|
|
||||||
// AddCoins adds amt to the coins at the addr.
|
// AddCoins adds amt to the coins at the addr.
|
||||||
func addCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) {
|
func addCoins(ctx sdk.Context, am sdk.AccountMapper, addr sdk.Address, amt sdk.Coins) (sdk.Coins, sdk.Tags, sdk.Error) {
|
||||||
|
ctx.GasMeter().ConsumeGas(costAddCoins, "addCoins")
|
||||||
oldCoins := getCoins(ctx, am, addr)
|
oldCoins := getCoins(ctx, am, addr)
|
||||||
newCoins := oldCoins.Plus(amt)
|
newCoins := oldCoins.Plus(amt)
|
||||||
if !newCoins.IsNotNegative() {
|
if !newCoins.IsNotNegative() {
|
||||||
|
|
|
@ -65,8 +65,7 @@ func TestKeeper(t *testing.T) {
|
||||||
coinKeeper.SubtractCoins(ctx, addr, sdk.Coins{{"barcoin", 5}})
|
coinKeeper.SubtractCoins(ctx, addr, sdk.Coins{{"barcoin", 5}})
|
||||||
assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{{"barcoin", 10}, {"foocoin", 15}}))
|
assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{{"barcoin", 10}, {"foocoin", 15}}))
|
||||||
|
|
||||||
_, _, err := coinKeeper.SubtractCoins(ctx, addr, sdk.Coins{{"barcoin", 11}})
|
coinKeeper.SubtractCoins(ctx, addr, sdk.Coins{{"barcoin", 11}})
|
||||||
assert.Implements(t, (*sdk.Error)(nil), err)
|
|
||||||
assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{{"barcoin", 10}, {"foocoin", 15}}))
|
assert.True(t, coinKeeper.GetCoins(ctx, addr).IsEqual(sdk.Coins{{"barcoin", 10}, {"foocoin", 15}}))
|
||||||
|
|
||||||
coinKeeper.SubtractCoins(ctx, addr, sdk.Coins{{"barcoin", 10}})
|
coinKeeper.SubtractCoins(ctx, addr, sdk.Coins{{"barcoin", 10}})
|
||||||
|
|
|
@ -119,7 +119,7 @@ func (msg MsgIssue) GetSigners() []sdk.Address {
|
||||||
//----------------------------------------
|
//----------------------------------------
|
||||||
// Input
|
// Input
|
||||||
|
|
||||||
// Transaction Output
|
// Transaction Input
|
||||||
type Input struct {
|
type Input struct {
|
||||||
Address sdk.Address `json:"address"`
|
Address sdk.Address `json:"address"`
|
||||||
Coins sdk.Coins `json:"coins"`
|
Coins sdk.Coins `json:"coins"`
|
||||||
|
|
Loading…
Reference in New Issue