From 4d0db39fb9b59b1aae6dd875699e8bcca9f3014e Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Thu, 29 Jun 2017 15:29:36 +0200 Subject: [PATCH] Abstracts away from pubkey addr -> app/chain-specific "actors" --- context.go | 20 +++++++++++++------- handlers/base.go | 8 ++++---- handlers/sigs.go | 6 +++--- stack/context.go | 6 +++--- txs/base.go | 10 +++++----- txs/send.go | 21 +++++++++++---------- 6 files changed, 39 insertions(+), 32 deletions(-) diff --git a/context.go b/context.go index 21b91deb8..704ac49cc 100644 --- a/context.go +++ b/context.go @@ -2,21 +2,27 @@ package basecoin import "github.com/tendermint/go-wire/data" -type Permission struct { - App string // Which app authorized this? - Address data.Bytes // App-specific identifier +// Actor abstracts any address that can authorize actions, hold funds, +// or initiate any sort of transaction. +// +// It doesn't just have to be a pubkey on this chain, it could stem from +// another app (like multi-sig account), or even another chain (via IBC) +type Actor struct { + ChainID string // this is empty unless it comes from a different chain + App string // the app that the actor belongs to + Address data.Bytes // arbitrary app-specific unique id } -func NewPermission(app string, addr []byte) Permission { - return Permission{App: app, Address: addr} +func NewActor(app string, addr []byte) Actor { + return Actor{App: app, Address: addr} } // Context is an interface, so we can implement "secure" variants that // rely on private fields to control the actions type Context interface { // context.Context - WithPermissions(perms ...Permission) Context - HasPermission(perm Permission) bool + WithPermissions(perms ...Actor) Context + HasPermission(perm Actor) bool IsParent(ctx Context) bool Reset() Context } diff --git a/handlers/base.go b/handlers/base.go index 3b4c6b4be..0d6781940 100644 --- a/handlers/base.go +++ b/handlers/base.go @@ -13,11 +13,11 @@ const ( type AccountChecker interface { // Get amount checks the current amount - GetAmount(store types.KVStore, addr []byte) (types.Coins, error) + GetAmount(store types.KVStore, addr basecoin.Actor) (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) + ChangeAmount(store types.KVStore, addr basecoin.Actor, coins types.Coins) (types.Coins, error) } type SimpleFeeHandler struct { @@ -44,7 +44,7 @@ func (h SimpleFeeHandler) CheckTx(ctx basecoin.Context, store types.KVStore, tx return res, errors.InsufficientFees() } - if !ctx.HasPermission(SigPerm(feeTx.Payer)) { + if !ctx.HasPermission(feeTx.Payer) { return res, errors.Unauthorized() } @@ -67,7 +67,7 @@ func (h SimpleFeeHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, t return res, errors.InsufficientFees() } - if !ctx.HasPermission(SigPerm(feeTx.Payer)) { + if !ctx.HasPermission(feeTx.Payer) { return res, errors.Unauthorized() } diff --git a/handlers/sigs.go b/handlers/sigs.go index eb8136680..81292222c 100644 --- a/handlers/sigs.go +++ b/handlers/sigs.go @@ -23,8 +23,8 @@ func (_ SignedHandler) Name() string { var _ basecoin.Middleware = SignedHandler{} -func SigPerm(addr []byte) basecoin.Permission { - return basecoin.Permission{App: NameSigs, Address: addr} +func SigPerm(addr []byte) basecoin.Actor { + return basecoin.NewActor(NameSigs, addr) } // Signed allows us to use txs.OneSig and txs.MultiSig (and others??) @@ -52,7 +52,7 @@ func (h SignedHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, tx b } func addSigners(ctx basecoin.Context, sigs []crypto.PubKey) basecoin.Context { - perms := make([]basecoin.Permission, len(sigs)) + perms := make([]basecoin.Actor, len(sigs)) for i, s := range sigs { perms[i] = SigPerm(s.Address()) } diff --git a/stack/context.go b/stack/context.go index cd1b89302..2ff81b50a 100644 --- a/stack/context.go +++ b/stack/context.go @@ -15,7 +15,7 @@ type nonce int64 type secureContext struct { id nonce app string - perms []basecoin.Permission + perms []basecoin.Actor } func NewContext() basecoin.Context { @@ -27,7 +27,7 @@ func NewContext() basecoin.Context { var _ basecoin.Context = secureContext{} // WithPermissions will panic if they try to set permission without the proper app -func (c secureContext) WithPermissions(perms ...basecoin.Permission) basecoin.Context { +func (c secureContext) WithPermissions(perms ...basecoin.Actor) basecoin.Context { // the guard makes sure you only set permissions for the app you are inside for _, p := range perms { if p.App != c.app { @@ -42,7 +42,7 @@ func (c secureContext) WithPermissions(perms ...basecoin.Permission) basecoin.Co } } -func (c secureContext) HasPermission(perm basecoin.Permission) bool { +func (c secureContext) HasPermission(perm basecoin.Actor) bool { for _, p := range c.perms { if perm.App == p.App && bytes.Equal(perm.Address, p.Address) { return true diff --git a/txs/base.go b/txs/base.go index 915ca8f44..dfd764832 100644 --- a/txs/base.go +++ b/txs/base.go @@ -67,14 +67,14 @@ func NewRaw(d []byte) Raw { // Fee attaches a fee payment to the embedded tx type Fee struct { - Tx basecoin.Tx `json:"tx"` - Fee types.Coin `json:"fee"` - Payer data.Bytes `json:"payer"` // the address who pays the fee + Tx basecoin.Tx `json:"tx"` + Fee types.Coin `json:"fee"` + Payer basecoin.Actor `json:"payer"` // the address who pays the fee // Gas types.Coin `json:"gas"` // ????? } -func NewFee(tx basecoin.Tx, fee types.Coin, addr []byte) *Fee { - return &Fee{Tx: tx, Fee: fee, Payer: addr} +func NewFee(tx basecoin.Tx, fee types.Coin, payer basecoin.Actor) *Fee { + return &Fee{Tx: tx, Fee: fee, Payer: payer} } func (f *Fee) ValidateBasic() error { diff --git a/txs/send.go b/txs/send.go index cffcd47f1..225cdcc51 100644 --- a/txs/send.go +++ b/txs/send.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/tendermint/basecoin" - "github.com/tendermint/go-wire/data" "github.com/tendermint/basecoin/errors" "github.com/tendermint/basecoin/types" @@ -13,13 +12,14 @@ import ( //----------------------------------------------------------------------------- type TxInput struct { - Address data.Bytes `json:"address"` - Coins types.Coins `json:"coins"` - Sequence int `json:"sequence"` // Nonce: Must be 1 greater than the last committed TxInput + Address basecoin.Actor `json:"address"` + Coins types.Coins `json:"coins"` + Sequence int `json:"sequence"` // Nonce: Must be 1 greater than the last committed TxInput } func (txIn TxInput) ValidateBasic() error { - if len(txIn.Address) != 20 { + // TODO: knowledge of app-specific codings? + if txIn.Address.App == "" { return errors.InvalidAddress() } if !txIn.Coins.IsValid() { @@ -38,7 +38,7 @@ func (txIn TxInput) String() string { return fmt.Sprintf("TxInput{%v,%v,%v}", txIn.Address, txIn.Coins, txIn.Sequence) } -func NewTxInput(addr []byte, coins types.Coins, sequence int) TxInput { +func NewTxInput(addr basecoin.Actor, coins types.Coins, sequence int) TxInput { input := TxInput{ Address: addr, Coins: coins, @@ -50,12 +50,13 @@ func NewTxInput(addr []byte, coins types.Coins, sequence int) TxInput { //----------------------------------------------------------------------------- type TxOutput struct { - Address data.Bytes `json:"address"` - Coins types.Coins `json:"coins"` + Address basecoin.Actor `json:"address"` + Coins types.Coins `json:"coins"` } func (txOut TxOutput) ValidateBasic() error { - if len(txOut.Address) != 20 { + // TODO: knowledge of app-specific codings? + if txOut.Address.App == "" { return errors.InvalidAddress() } if !txOut.Coins.IsValid() { @@ -71,7 +72,7 @@ func (txOut TxOutput) String() string { return fmt.Sprintf("TxOutput{%X,%v}", txOut.Address, txOut.Coins) } -func NewTxOutput(addr []byte, coins types.Coins) TxOutput { +func NewTxOutput(addr basecoin.Actor, coins types.Coins) TxOutput { output := TxOutput{ Address: addr, Coins: coins,