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"
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
}

View File

@ -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()
}

View File

@ -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())
}

View File

@ -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

View File

@ -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 {

View File

@ -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,