Add fee handler and signer handler to show how layering works
This commit is contained in:
parent
f4393511ee
commit
ab72ca881e
|
@ -11,8 +11,10 @@ const (
|
|||
msgUnauthorized = "Unauthorized"
|
||||
msgInvalidAddress = "Invalid Address"
|
||||
msgInvalidCoins = "Invalid Coins"
|
||||
msgInvalidFormat = "Invalid Format"
|
||||
msgInvalidSequence = "Invalid Sequence"
|
||||
msgInvalidSignature = "Invalid Signature"
|
||||
msgInsufficientFees = "Insufficient Fees"
|
||||
msgNoInputs = "No Input Coins"
|
||||
msgNoOutputs = "No Output Coins"
|
||||
msgTooLarge = "Input size too large"
|
||||
|
@ -48,10 +50,18 @@ func InvalidCoins() TMError {
|
|||
return New(msgInvalidCoins, abci.CodeType_BaseInvalidInput)
|
||||
}
|
||||
|
||||
func InvalidFormat() TMError {
|
||||
return New(msgInvalidFormat, abci.CodeType_BaseInvalidInput)
|
||||
}
|
||||
|
||||
func InvalidSequence() TMError {
|
||||
return New(msgInvalidSequence, abci.CodeType_BaseInvalidInput)
|
||||
}
|
||||
|
||||
func InsufficientFees() TMError {
|
||||
return New(msgInsufficientFees, abci.CodeType_BaseInvalidInput)
|
||||
}
|
||||
|
||||
func NoInputs() TMError {
|
||||
return New(msgNoInputs, abci.CodeType_BaseInvalidInput)
|
||||
}
|
||||
|
|
20
handler.go
20
handler.go
|
@ -1,6 +1,8 @@
|
|||
package basecoin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-wire/data"
|
||||
|
@ -38,6 +40,24 @@ func (c Context) GetSigners() []crypto.PubKey {
|
|||
return c.sigs
|
||||
}
|
||||
|
||||
func (c Context) IsSignerAddr(addr []byte) bool {
|
||||
for _, pk := range c.sigs {
|
||||
if bytes.Equal(addr, pk.Address()) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c Context) IsSignerKey(key crypto.PubKey) bool {
|
||||
for _, pk := range c.sigs {
|
||||
if key.Equals(pk) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Result captures any non-error abci result
|
||||
// to make sure people use error for error cases
|
||||
type Result struct {
|
||||
|
|
|
@ -1,61 +1,77 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
"github.com/tendermint/basecoin/txs"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
type SignedHandler struct {
|
||||
AllowMultiSig bool
|
||||
Inner basecoin.Handler
|
||||
type AccountChecker interface {
|
||||
// Get amount checks the current amount
|
||||
GetAmount(store types.KVStore, addr []byte) (types.Coins, error)
|
||||
|
||||
// ChangeAmount modifies the balance by the given amount and returns the new balance
|
||||
// always returns an error if leading to negative balance
|
||||
ChangeAmount(store types.KVStore, addr []byte, coins types.Coins) (types.Coins, error)
|
||||
}
|
||||
|
||||
func (h SignedHandler) Next() basecoin.Handler {
|
||||
type SimpleFeeHandler struct {
|
||||
AccountChecker
|
||||
MinFee types.Coins
|
||||
Inner basecoin.Handler
|
||||
}
|
||||
|
||||
func (h SimpleFeeHandler) Next() basecoin.Handler {
|
||||
return h.Inner
|
||||
}
|
||||
|
||||
var _ basecoin.Handler = SignedHandler{}
|
||||
var _ basecoin.Handler = SimpleFeeHandler{}
|
||||
|
||||
type Signed interface {
|
||||
basecoin.TxLayer
|
||||
Signers() ([]crypto.PubKey, error)
|
||||
}
|
||||
// Yes, I know refactor a bit... really too late already
|
||||
|
||||
func (h SignedHandler) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||
var sigs []crypto.PubKey
|
||||
|
||||
stx, ok := tx.Unwrap().(Signed)
|
||||
func (h SimpleFeeHandler) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||
feeTx, ok := tx.Unwrap().(*txs.Fee)
|
||||
if !ok {
|
||||
return res, errors.InvalidFormat()
|
||||
}
|
||||
|
||||
fees := types.Coins{feeTx.Fee}
|
||||
if !fees.IsGTE(h.MinFee) {
|
||||
return res, errors.InsufficientFees()
|
||||
}
|
||||
|
||||
if !ctx.IsSignerAddr(feeTx.Payer) {
|
||||
return res, errors.Unauthorized()
|
||||
}
|
||||
|
||||
sigs, err = stx.Signers()
|
||||
_, err = h.ChangeAmount(store, feeTx.Payer, fees.Negative())
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// add the signers to the context and continue
|
||||
ctx2 := ctx.AddSigners(sigs...)
|
||||
return h.Next().CheckTx(ctx2, store, stx.Next())
|
||||
return basecoin.Result{Log: "Valid tx"}, nil
|
||||
}
|
||||
|
||||
func (h SignedHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||
var sigs []crypto.PubKey
|
||||
|
||||
stx, ok := tx.Unwrap().(Signed)
|
||||
func (h SimpleFeeHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||
feeTx, ok := tx.Unwrap().(*txs.Fee)
|
||||
if !ok {
|
||||
return res, errors.InvalidFormat()
|
||||
}
|
||||
|
||||
fees := types.Coins{feeTx.Fee}
|
||||
if !fees.IsGTE(h.MinFee) {
|
||||
return res, errors.InsufficientFees()
|
||||
}
|
||||
|
||||
if !ctx.IsSignerAddr(feeTx.Payer) {
|
||||
return res, errors.Unauthorized()
|
||||
}
|
||||
|
||||
sigs, err = stx.Signers()
|
||||
_, err = h.ChangeAmount(store, feeTx.Payer, fees.Negative())
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// add the signers to the context and continue
|
||||
ctx2 := ctx.AddSigners(sigs...)
|
||||
return h.Next().DeliverTx(ctx2, store, stx.Next())
|
||||
return h.Next().DeliverTx(ctx, store, feeTx.Next())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
"github.com/tendermint/basecoin"
|
||||
"github.com/tendermint/basecoin/errors"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
type SignedHandler struct {
|
||||
AllowMultiSig bool
|
||||
Inner basecoin.Handler
|
||||
}
|
||||
|
||||
func (h SignedHandler) Next() basecoin.Handler {
|
||||
return h.Inner
|
||||
}
|
||||
|
||||
var _ basecoin.Handler = SignedHandler{}
|
||||
|
||||
type Signed interface {
|
||||
basecoin.TxLayer
|
||||
Signers() ([]crypto.PubKey, error)
|
||||
}
|
||||
|
||||
func (h SignedHandler) CheckTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||
var sigs []crypto.PubKey
|
||||
|
||||
stx, ok := tx.Unwrap().(Signed)
|
||||
if !ok {
|
||||
return res, errors.Unauthorized()
|
||||
}
|
||||
|
||||
sigs, err = stx.Signers()
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// add the signers to the context and continue
|
||||
ctx2 := ctx.AddSigners(sigs...)
|
||||
return h.Next().CheckTx(ctx2, store, stx.Next())
|
||||
}
|
||||
|
||||
func (h SignedHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx basecoin.Tx) (res basecoin.Result, err error) {
|
||||
var sigs []crypto.PubKey
|
||||
|
||||
stx, ok := tx.Unwrap().(Signed)
|
||||
if !ok {
|
||||
return res, errors.Unauthorized()
|
||||
}
|
||||
|
||||
sigs, err = stx.Signers()
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// add the signers to the context and continue
|
||||
ctx2 := ctx.AddSigners(sigs...)
|
||||
return h.Next().DeliverTx(ctx2, store, stx.Next())
|
||||
}
|
|
@ -86,6 +86,10 @@ func (f *Fee) Wrap() basecoin.Tx {
|
|||
return basecoin.Tx{f}
|
||||
}
|
||||
|
||||
func (f *Fee) Next() basecoin.Tx {
|
||||
return f.Tx
|
||||
}
|
||||
|
||||
/**** MultiTx ******/
|
||||
type MultiTx struct {
|
||||
Txs []basecoin.Tx `json:"txs"`
|
||||
|
|
Loading…
Reference in New Issue