Add issuer position to grant credit

This commit is contained in:
Ethan Frey 2017-07-21 20:24:53 +02:00
parent 89a8c0bf08
commit 6135345af8
5 changed files with 139 additions and 24 deletions

View File

@ -120,7 +120,10 @@ func GetGenesisJSON(chainID, addr string) string {
"amount": 9007199254740992
}
]
}]
}],
"plugin_options": [
"coin/issuer", {"app": "sigs", "address": "%s"}
]
}
}`, chainID, addr)
}`, chainID, addr, addr)
}

View File

@ -1,8 +1,6 @@
package coin
import (
"fmt"
"github.com/tendermint/go-wire/data"
"github.com/tendermint/tmlibs/log"
@ -83,7 +81,6 @@ func (h Handler) DeliverTx(ctx basecoin.Context, store state.SimpleDB,
out.Address.ChainID = ""
}
fmt.Printf("Giving %#v to %#v\n\n", out.Coins, out.Address)
_, err = ChangeCoins(store, out.Address, out.Coins)
if err != nil {
return res, err
@ -117,25 +114,11 @@ func (h Handler) SetOption(l log.Logger, store state.SimpleDB,
if module != NameCoin {
return "", errors.ErrUnknownModule(module)
}
if key == "account" {
var acc GenesisAccount
err = data.FromJSON([]byte(value), &acc)
if err != nil {
return "", err
}
acc.Balance.Sort()
addr, err := acc.GetAddr()
if err != nil {
return "", ErrInvalidAddress()
}
// this sets the permission for a public key signature, use that app
actor := auth.SigPerm(addr)
err = storeAccount(store, actor.Bytes(), acc.ToAccount())
if err != nil {
return "", err
}
return "Success", nil
switch key {
case "account":
return setAccount(store, value)
case "issuer":
return setIssuer(store, value)
}
return "", errors.ErrUnknownKey(key)
}
@ -159,3 +142,38 @@ func checkTx(ctx basecoin.Context, tx basecoin.Tx) (send SendTx, err error) {
}
return send, nil
}
func setAccount(store state.KVStore, value string) (log string, err error) {
var acc GenesisAccount
err = data.FromJSON([]byte(value), &acc)
if err != nil {
return "", err
}
acc.Balance.Sort()
addr, err := acc.GetAddr()
if err != nil {
return "", ErrInvalidAddress()
}
// this sets the permission for a public key signature, use that app
actor := auth.SigPerm(addr)
err = storeAccount(store, actor.Bytes(), acc.ToAccount())
if err != nil {
return "", err
}
return "Success", nil
}
// setIssuer sets a permission for some super-powerful account to
// mint money
func setIssuer(store state.KVStore, value string) (log string, err error) {
var issuer basecoin.Actor
err = data.FromJSON([]byte(value), &issuer)
if err != nil {
return "", err
}
err = storeIssuer(store, issuer)
if err != nil {
return "", err
}
return "Success", nil
}

View File

@ -216,3 +216,34 @@ func TestSetOption(t *testing.T) {
}
}
}
func TestSetIssuer(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
cases := []struct {
issuer basecoin.Actor
}{
{basecoin.Actor{App: "sig", Address: []byte("gwkfgk")}},
// and set back to empty (nil is valid, but assert.Equals doesn't match)
{basecoin.Actor{Address: []byte{}}},
{basecoin.Actor{ChainID: "other", App: "role", Address: []byte("vote")}},
}
h := NewHandler()
l := log.NewNopLogger()
for i, tc := range cases {
store := state.NewMemKVStore()
key := "issuer"
value, err := json.Marshal(tc.issuer)
require.Nil(err, "%d,%d: %+v", i, err)
_, err = h.SetOption(l, store, NameCoin, key, string(value), nil)
require.Nil(err, "%+v", err)
// check state is proper
info, err := loadHandlerInfo(store)
assert.Nil(err, "%d: %+v", i, err)
assert.Equal(tc.issuer, info.Issuer)
}
}

View File

@ -84,7 +84,11 @@ func updateCoins(store state.SimpleDB, addr basecoin.Actor, coins Coins) (acct A
// Account - coin account structure
type Account struct {
// Coins is how much is on the account
Coins Coins `json:"coins"`
// Credit is how much has been "fronted" to the account
// (this is usually 0 except for trusted chains)
Credit Coins `json:"credit"`
}
func loadAccount(store state.SimpleDB, key []byte) (acct Account, err error) {
@ -107,3 +111,35 @@ func storeAccount(store state.SimpleDB, key []byte, acct Account) error {
store.Set(key, bin)
return nil // real stores can return error...
}
// HandlerInfo - this is global info on the coin handler
type HandlerInfo struct {
Issuer basecoin.Actor `json:"issuer"`
}
// TODO: where to store these special pieces??
var handlerKey = []byte{12, 34}
func loadHandlerInfo(store state.KVStore) (info HandlerInfo, err error) {
data := store.Get(handlerKey)
if len(data) == 0 {
return info, nil
}
err = wire.ReadBinaryBytes(data, &info)
if err != nil {
msg := "Error reading handler info"
return info, errors.ErrInternal(msg)
}
return info, nil
}
func storeIssuer(store state.KVStore, issuer basecoin.Actor) error {
info, err := loadHandlerInfo(store)
if err != nil {
return err
}
info.Issuer = issuer
d := wire.BinaryBytes(info)
store.Set(handlerKey, d)
return nil // real stores can return error...
}

View File

@ -157,3 +157,30 @@ func (tx SendTx) String() string {
func (tx SendTx) Wrap() basecoin.Tx {
return basecoin.Tx{tx}
}
//-----------------------------------------------------------------------------
// CreditTx - this allows a special issuer to give an account credit
// Satisfies: TxInner
type CreditTx struct {
Debitor basecoin.Actor `json:"debitor"`
// Credit is the amount to change the credit...
// This may be negative to remove some over-issued credit,
// but can never bring the credit or the balance to negative
Credit Coins `json:"credit"`
}
// NewCreditTx - modify the credit granted to a given account
func NewCreditTx(debitor basecoin.Actor, credit Coins) basecoin.Tx {
return CreditTx{Debitor: debitor, Credit: credit}.Wrap()
}
// Wrap - used to satisfy TxInner
func (tx CreditTx) Wrap() basecoin.Tx {
return basecoin.Tx{tx}
}
// ValidateBasic - used to satisfy TxInner
func (tx CreditTx) ValidateBasic() error {
return nil
}