diff --git a/modules/etc/handler.go b/modules/etc/handler.go index e9c06620d..ba338d5fb 100644 --- a/modules/etc/handler.go +++ b/modules/etc/handler.go @@ -1,6 +1,91 @@ package etc +import ( + "github.com/tendermint/basecoin" + "github.com/tendermint/basecoin/errors" + "github.com/tendermint/basecoin/state" + wire "github.com/tendermint/go-wire" +) + const ( // Name of the module for registering it Name = "etc" + + // CostSet is the gas needed for the set operation + CostSet uint64 = 10 + // CostRemove is the gas needed for the remove operation + CostRemove = 10 ) + +// Handler allows us to set and remove data +type Handler struct { + basecoin.NopInitState + basecoin.NopInitValidate +} + +var _ basecoin.Handler = Handler{} + +// NewHandler makes a role handler to modify data +func NewHandler() Handler { + return Handler{} +} + +// Name - return name space +func (Handler) Name() string { + return Name +} + +// CheckTx verifies if the transaction is properly formated +func (h Handler) CheckTx(ctx basecoin.Context, store state.SimpleDB, tx basecoin.Tx) (res basecoin.CheckResult, err error) { + err = tx.ValidateBasic() + if err != nil { + return + } + + switch tx.Unwrap().(type) { + case SetTx: + res = basecoin.NewCheck(CostSet, "") + case RemoveTx: + res = basecoin.NewCheck(CostRemove, "") + default: + err = errors.ErrUnknownTxType(tx) + } + return +} + +// DeliverTx tries to create a new role. +// +// Returns an error if the role already exists +func (h Handler) DeliverTx(ctx basecoin.Context, store state.SimpleDB, tx basecoin.Tx) (res basecoin.DeliverResult, err error) { + err = tx.ValidateBasic() + if err != nil { + return + } + + switch t := tx.Unwrap().(type) { + case SetTx: + res, err = h.doSetTx(ctx, store, t) + case RemoveTx: + res, err = h.doRemoveTx(ctx, store, t) + default: + err = errors.ErrUnknownTxType(tx) + } + return +} + +// doSetTx write to the store, overwriting any previous value +func (h Handler) doSetTx(ctx basecoin.Context, store state.SimpleDB, tx SetTx) (res basecoin.DeliverResult, err error) { + data := NewData(tx.Value, ctx.BlockHeight()) + store.Set(tx.Key, wire.BinaryBytes(data)) + return +} + +// doRemoveTx deletes the value from the store and returns the last value +func (h Handler) doRemoveTx(ctx basecoin.Context, store state.SimpleDB, tx RemoveTx) (res basecoin.DeliverResult, err error) { + // we set res.Data so it gets returned to the client over the abci interface + res.Data = store.Get(tx.Key) + if len(res.Data) != 0 { + store.Remove(tx.Key) + } + return +} diff --git a/modules/etc/store.go b/modules/etc/store.go index 825503c2e..4ec45d251 100644 --- a/modules/etc/store.go +++ b/modules/etc/store.go @@ -1 +1,20 @@ package etc + +import "github.com/tendermint/go-wire/data" + +// Data is the struct we use to store in the merkle tree +type Data struct { + // SetAt is the block height this was set at + SetAt uint64 `json:"created_at"` + // Value is the data that was stored. + // data.Bytes is like []byte but json encodes as hex not base64 + Value data.Bytes `json:"value"` +} + +// NewData creates a new Data item +func NewData(value []byte, setAt uint64) Data { + return Data{ + SetAt: setAt, + Value: value, + } +} diff --git a/modules/etc/tx.go b/modules/etc/tx.go index 80dbf4da0..cae743591 100644 --- a/modules/etc/tx.go +++ b/modules/etc/tx.go @@ -8,17 +8,16 @@ import ( // nolint const ( TypeSet = Name + "/set" - TypeGet = Name + "/get" TypeRemove = Name + "/remove" ByteSet = 0xF0 - ByteGet = 0xF1 ByteRemove = 0xF2 ) func init() { basecoin.TxMapper. - RegisterImplementation(SetTx{}, TypeSet, ByteSet) + RegisterImplementation(SetTx{}, TypeSet, ByteSet). + RegisterImplementation(RemoveTx{}, TypeRemove, ByteRemove) } // SetTx sets a key-value pair @@ -39,3 +38,21 @@ func (t SetTx) ValidateBasic() error { } return nil } + +// RemoveTx deletes the value at this key, returns old value +type RemoveTx struct { + Key data.Bytes `json:"key"` +} + +// Wrap - fulfills TxInner interface +func (t RemoveTx) Wrap() basecoin.Tx { + return basecoin.Tx{t} +} + +// ValidateBasic makes sure it is valid +func (t RemoveTx) ValidateBasic() error { + if len(t.Key) == 0 { + return ErrMissingData() + } + return nil +}