Abstracts away from pubkey addr -> app/chain-specific "actors"
This commit is contained in:
parent
1caeec218f
commit
4d0db39fb9
20
context.go
20
context.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
10
txs/base.go
10
txs/base.go
|
@ -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 {
|
||||||
|
|
21
txs/send.go
21
txs/send.go
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue