Abstracts away from pubkey addr -> app/chain-specific "actors"

This commit is contained in:
Ethan Frey 2017-06-29 15:29:36 +02:00
parent 1caeec218f
commit 4d0db39fb9
6 changed files with 39 additions and 32 deletions

View File

@ -2,21 +2,27 @@ package basecoin
import "github.com/tendermint/go-wire/data" import "github.com/tendermint/go-wire/data"
type Permission struct { // Actor abstracts any address that can authorize actions, hold funds,
App string // Which app authorized this? // or initiate any sort of transaction.
Address data.Bytes // App-specific identifier //
// 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 { func NewActor(app string, addr []byte) Actor {
return Permission{App: app, Address: addr} return Actor{App: app, Address: addr}
} }
// Context is an interface, so we can implement "secure" variants that // Context is an interface, so we can implement "secure" variants that
// rely on private fields to control the actions // rely on private fields to control the actions
type Context interface { type Context interface {
// context.Context // context.Context
WithPermissions(perms ...Permission) Context WithPermissions(perms ...Actor) Context
HasPermission(perm Permission) bool HasPermission(perm Actor) bool
IsParent(ctx Context) bool IsParent(ctx Context) bool
Reset() Context Reset() Context
} }

View File

@ -13,11 +13,11 @@ const (
type AccountChecker interface { type AccountChecker interface {
// Get amount checks the current amount // 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 // ChangeAmount modifies the balance by the given amount and returns the new balance
// always returns an error if leading to negative 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 { type SimpleFeeHandler struct {
@ -44,7 +44,7 @@ func (h SimpleFeeHandler) CheckTx(ctx basecoin.Context, store types.KVStore, tx
return res, errors.InsufficientFees() return res, errors.InsufficientFees()
} }
if !ctx.HasPermission(SigPerm(feeTx.Payer)) { if !ctx.HasPermission(feeTx.Payer) {
return res, errors.Unauthorized() return res, errors.Unauthorized()
} }
@ -67,7 +67,7 @@ func (h SimpleFeeHandler) DeliverTx(ctx basecoin.Context, store types.KVStore, t
return res, errors.InsufficientFees() return res, errors.InsufficientFees()
} }
if !ctx.HasPermission(SigPerm(feeTx.Payer)) { if !ctx.HasPermission(feeTx.Payer) {
return res, errors.Unauthorized() return res, errors.Unauthorized()
} }

View File

@ -23,8 +23,8 @@ func (_ SignedHandler) Name() string {
var _ basecoin.Middleware = SignedHandler{} var _ basecoin.Middleware = SignedHandler{}
func SigPerm(addr []byte) basecoin.Permission { func SigPerm(addr []byte) basecoin.Actor {
return basecoin.Permission{App: NameSigs, Address: addr} return basecoin.NewActor(NameSigs, addr)
} }
// Signed allows us to use txs.OneSig and txs.MultiSig (and others??) // 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 { 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 { for i, s := range sigs {
perms[i] = SigPerm(s.Address()) perms[i] = SigPerm(s.Address())
} }

View File

@ -15,7 +15,7 @@ type nonce int64
type secureContext struct { type secureContext struct {
id nonce id nonce
app string app string
perms []basecoin.Permission perms []basecoin.Actor
} }
func NewContext() basecoin.Context { func NewContext() basecoin.Context {
@ -27,7 +27,7 @@ func NewContext() basecoin.Context {
var _ basecoin.Context = secureContext{} var _ basecoin.Context = secureContext{}
// WithPermissions will panic if they try to set permission without the proper app // 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 // the guard makes sure you only set permissions for the app you are inside
for _, p := range perms { for _, p := range perms {
if p.App != c.app { 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 { for _, p := range c.perms {
if perm.App == p.App && bytes.Equal(perm.Address, p.Address) { if perm.App == p.App && bytes.Equal(perm.Address, p.Address) {
return true return true

View File

@ -67,14 +67,14 @@ func NewRaw(d []byte) Raw {
// Fee attaches a fee payment to the embedded tx // Fee attaches a fee payment to the embedded tx
type Fee struct { type Fee struct {
Tx basecoin.Tx `json:"tx"` Tx basecoin.Tx `json:"tx"`
Fee types.Coin `json:"fee"` Fee types.Coin `json:"fee"`
Payer data.Bytes `json:"payer"` // the address who pays the fee Payer basecoin.Actor `json:"payer"` // the address who pays the fee
// Gas types.Coin `json:"gas"` // ????? // Gas types.Coin `json:"gas"` // ?????
} }
func NewFee(tx basecoin.Tx, fee types.Coin, addr []byte) *Fee { func NewFee(tx basecoin.Tx, fee types.Coin, payer basecoin.Actor) *Fee {
return &Fee{Tx: tx, Fee: fee, Payer: addr} return &Fee{Tx: tx, Fee: fee, Payer: payer}
} }
func (f *Fee) ValidateBasic() error { func (f *Fee) ValidateBasic() error {

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"github.com/tendermint/basecoin" "github.com/tendermint/basecoin"
"github.com/tendermint/go-wire/data"
"github.com/tendermint/basecoin/errors" "github.com/tendermint/basecoin/errors"
"github.com/tendermint/basecoin/types" "github.com/tendermint/basecoin/types"
@ -13,13 +12,14 @@ import (
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
type TxInput struct { type TxInput struct {
Address data.Bytes `json:"address"` Address basecoin.Actor `json:"address"`
Coins types.Coins `json:"coins"` Coins types.Coins `json:"coins"`
Sequence int `json:"sequence"` // Nonce: Must be 1 greater than the last committed TxInput Sequence int `json:"sequence"` // Nonce: Must be 1 greater than the last committed TxInput
} }
func (txIn TxInput) ValidateBasic() error { func (txIn TxInput) ValidateBasic() error {
if len(txIn.Address) != 20 { // TODO: knowledge of app-specific codings?
if txIn.Address.App == "" {
return errors.InvalidAddress() return errors.InvalidAddress()
} }
if !txIn.Coins.IsValid() { 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) 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{ input := TxInput{
Address: addr, Address: addr,
Coins: coins, Coins: coins,
@ -50,12 +50,13 @@ func NewTxInput(addr []byte, coins types.Coins, sequence int) TxInput {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
type TxOutput struct { type TxOutput struct {
Address data.Bytes `json:"address"` Address basecoin.Actor `json:"address"`
Coins types.Coins `json:"coins"` Coins types.Coins `json:"coins"`
} }
func (txOut TxOutput) ValidateBasic() error { func (txOut TxOutput) ValidateBasic() error {
if len(txOut.Address) != 20 { // TODO: knowledge of app-specific codings?
if txOut.Address.App == "" {
return errors.InvalidAddress() return errors.InvalidAddress()
} }
if !txOut.Coins.IsValid() { if !txOut.Coins.IsValid() {
@ -71,7 +72,7 @@ func (txOut TxOutput) String() string {
return fmt.Sprintf("TxOutput{%X,%v}", txOut.Address, txOut.Coins) 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{ output := TxOutput{
Address: addr, Address: addr,
Coins: coins, Coins: coins,