cosmos-sdk/types/context.go

251 lines
5.4 KiB
Go
Raw Normal View History

2017-11-26 02:19:17 -08:00
package types
import (
"context"
2018-01-12 13:48:54 -08:00
"sync"
2017-12-21 23:30:14 -08:00
"github.com/golang/protobuf/proto"
abci "github.com/tendermint/abci/types"
2017-11-26 02:19:17 -08:00
)
// TODO: Add a default logger.
2017-12-21 23:30:14 -08:00
/*
2018-01-11 20:18:58 -08:00
The intent of Context is for it to be an immutable object that can be
cloned and updated cheaply with WithValue() and passed forward to the
next decorator or handler. For example,
2017-12-21 23:30:14 -08:00
2018-01-20 15:03:35 -08:00
func MsgHandler(ctx Context, tx Tx) Result {
...
ctx = ctx.WithValue(key, value)
...
}
2018-01-11 20:18:58 -08:00
*/
type Context struct {
2017-11-26 02:19:17 -08:00
context.Context
2018-01-11 20:18:58 -08:00
pst *thePast
gen int
// Don't add any other fields here,
// it's probably not what you want to do.
2017-11-26 02:19:17 -08:00
}
func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, txBytes []byte) Context {
2018-01-11 20:18:58 -08:00
c := Context{
Context: context.Background(),
pst: newThePast(),
gen: 0,
}
c = c.withMultiStore(ms)
2018-01-11 20:18:58 -08:00
c = c.withBlockHeader(header)
c = c.withBlockHeight(header.Height)
c = c.withChainID(header.ChainID)
c = c.withIsCheckTx(isCheckTx)
c = c.withTxBytes(txBytes)
2017-11-26 02:19:17 -08:00
return c
}
2018-01-11 20:18:58 -08:00
//----------------------------------------
// Getting a value
2018-01-11 20:18:58 -08:00
2017-12-21 23:30:14 -08:00
func (c Context) Value(key interface{}) interface{} {
value := c.Context.Value(key)
2018-01-11 20:18:58 -08:00
if cloner, ok := value.(cloner); ok {
2017-12-21 23:30:14 -08:00
return cloner.Clone()
}
if message, ok := value.(proto.Message); ok {
return proto.Clone(message)
}
return value
}
// KVStore fetches a KVStore from the MultiStore.
2018-01-12 14:30:02 -08:00
func (c Context) KVStore(key SubstoreKey) KVStore {
return c.multiStore().GetKVStore(key)
}
2018-01-11 20:18:58 -08:00
//----------------------------------------
// With* (setting a value)
2018-01-11 20:18:58 -08:00
func (c Context) WithValue(key interface{}, value interface{}) Context {
2017-12-21 23:30:14 -08:00
return c.withValue(key, value)
2017-11-26 02:19:17 -08:00
}
2018-01-11 20:18:58 -08:00
func (c Context) WithCloner(key interface{}, value cloner) Context {
2017-12-21 23:30:14 -08:00
return c.withValue(key, value)
}
2018-01-10 20:11:44 -08:00
func (c Context) WithCacheWrapper(key interface{}, value CacheWrapper) Context {
2017-12-21 23:30:14 -08:00
return c.withValue(key, value)
}
2018-01-10 20:11:44 -08:00
func (c Context) WithProtoMsg(key interface{}, value proto.Message) Context {
2017-12-21 23:30:14 -08:00
return c.withValue(key, value)
}
2018-01-12 14:30:02 -08:00
func (c Context) WithMultiStore(key SubstoreKey, ms MultiStore) Context {
return c.withValue(key, ms)
}
2018-01-10 20:11:44 -08:00
func (c Context) WithString(key interface{}, value string) Context {
2017-12-21 23:30:14 -08:00
return c.withValue(key, value)
}
2018-01-10 20:11:44 -08:00
func (c Context) WithInt32(key interface{}, value int32) Context {
2017-12-21 23:30:14 -08:00
return c.withValue(key, value)
}
2018-01-10 20:11:44 -08:00
func (c Context) WithUint32(key interface{}, value uint32) Context {
return c.withValue(key, value)
}
func (c Context) WithUint64(key interface{}, value uint64) Context {
2017-12-21 23:30:14 -08:00
return c.withValue(key, value)
}
func (c Context) withValue(key interface{}, value interface{}) Context {
2018-01-11 20:18:58 -08:00
c.pst.bump(Op{
gen: c.gen + 1,
key: key,
value: value,
}) // increment version for all relatives.
return Context{
Context: context.WithValue(c.Context, key, value),
pst: c.pst,
gen: c.gen + 1,
}
2017-11-26 02:19:17 -08:00
}
//----------------------------------------
// Values that require no key.
2017-11-26 02:19:17 -08:00
type contextKey int // local to the context module
const (
contextKeyMultiStore contextKey = iota
contextKeyBlockHeader
2017-11-26 02:19:17 -08:00
contextKeyBlockHeight
contextKeyChainID
contextKeyIsCheckTx
contextKeyTxBytes
2017-11-26 02:19:17 -08:00
)
// NOTE: Do not expose MultiStore, to require the store key.
func (c Context) multiStore() MultiStore {
return c.Value(contextKeyMultiStore).(MultiStore)
}
func (c Context) BlockHeader() abci.Header {
return c.Value(contextKeyBlockHeader).(abci.Header)
2017-11-26 02:19:17 -08:00
}
func (c Context) BlockHeight() int64 {
2017-11-26 20:29:17 -08:00
return c.Value(contextKeyBlockHeight).(int64)
}
func (c Context) ChainID() string {
2017-11-26 20:29:17 -08:00
return c.Value(contextKeyChainID).(string)
}
func (c Context) IsCheckTx() bool {
return c.Value(contextKeyIsCheckTx).(bool)
}
func (c Context) TxBytes() []byte {
return c.Value(contextKeyTxBytes).([]byte)
}
// Unexposed to prevent overriding.
func (c Context) withMultiStore(ms MultiStore) Context {
return c.withValue(contextKeyMultiStore, ms)
2018-01-10 20:11:44 -08:00
}
2017-11-26 02:19:17 -08:00
// Unexposed to prevent overriding.
2018-01-11 20:18:58 -08:00
func (c Context) withBlockHeader(header abci.Header) Context {
2017-12-22 00:23:37 -08:00
var _ proto.Message = &header // for cloning.
2017-12-21 23:30:14 -08:00
return c.withValue(contextKeyBlockHeader, header)
2017-11-26 02:19:17 -08:00
}
// Unexposed to prevent overriding.
2018-01-11 20:18:58 -08:00
func (c Context) withBlockHeight(height int64) Context {
2017-12-21 23:30:14 -08:00
return c.withValue(contextKeyBlockHeight, height)
2017-11-26 02:19:17 -08:00
}
// Unexposed to prevent overriding.
2018-01-11 20:18:58 -08:00
func (c Context) withChainID(chainID string) Context {
2017-12-21 23:30:14 -08:00
return c.withValue(contextKeyChainID, chainID)
2017-11-26 02:19:17 -08:00
}
// Unexposed to prevent overriding.
2018-01-11 20:18:58 -08:00
func (c Context) withIsCheckTx(isCheckTx bool) Context {
2017-12-21 23:30:14 -08:00
return c.withValue(contextKeyIsCheckTx, isCheckTx)
}
// Unexposed to prevent overriding.
2018-01-11 20:18:58 -08:00
func (c Context) withTxBytes(txBytes []byte) Context {
2017-12-21 23:30:14 -08:00
return c.withValue(contextKeyTxBytes, txBytes)
}
2018-01-11 20:18:58 -08:00
//----------------------------------------
// thePast
// Returns false if ver > 0.
// The first operation is version 1.
func (c Context) GetOp(ver int64) (Op, bool) {
return c.pst.getOp(ver)
}
//----------------------------------------
// Misc.
type cloner interface {
Clone() interface{} // deep copy
}
type Op struct {
// type is always 'with'
gen int
key interface{}
value interface{}
}
type thePast struct {
mtx sync.RWMutex
ver int
ops []Op
}
func newThePast() *thePast {
return &thePast{
2018-01-12 13:48:54 -08:00
ver: 0,
2018-01-11 20:18:58 -08:00
ops: nil,
}
}
func (pst *thePast) bump(op Op) {
pst.mtx.Lock()
pst.ver += 1
pst.ops = append(pst.ops, op)
pst.mtx.Unlock()
}
func (pst *thePast) version() int {
pst.mtx.RLock()
defer pst.mtx.RUnlock()
return pst.ver
}
// Returns false if ver > 0.
// The first operation is version 1.
2018-01-12 13:48:54 -08:00
func (pst *thePast) getOp(ver int64) (Op, bool) {
2018-01-11 20:18:58 -08:00
pst.mtx.RLock()
defer pst.mtx.RUnlock()
2018-01-12 13:48:54 -08:00
l := int64(len(pst.ops))
if l < ver {
2018-01-11 20:18:58 -08:00
return Op{}, false
} else {
return pst.ops[ver-1], true
}
}