Plugins and AccountCaches

This commit is contained in:
Jae Kwon 2016-03-24 12:17:26 -07:00
parent 83e7c9dab1
commit 964a4cfd50
7 changed files with 115 additions and 22 deletions

View File

@ -20,11 +20,13 @@ type Basecoin struct {
}
func NewBasecoin(eyesCli *eyes.Client) *Basecoin {
state_ := state.NewState(eyesCli)
govMint := gov.NewGovernmint(eyesCli)
state_.RegisterPlugin([]byte("gov"), govMint)
return &Basecoin{
eyesCli: eyesCli,
govMint: govMint,
state: state.NewState(eyesCli),
state: state_,
}
}

46
state/account_cache.go Normal file
View File

@ -0,0 +1,46 @@
package state
import (
"github.com/tendermint/basecoin/types"
"sort"
)
type AccountCache struct {
state *State
accounts map[string]*types.Account
}
func NewAccountCache(state *State) *AccountCache {
return &AccountCache{
state: state,
accounts: make(map[string]*types.Account),
}
}
func (cache *AccountCache) GetAccount(addr []byte) *types.Account {
acc, ok := cache.accounts[string(addr)]
if !ok {
acc = cache.state.GetAccount(addr)
cache.accounts[string(addr)] = acc
}
return acc
}
func (cache *AccountCache) SetAccount(addr []byte, acc *types.Account) {
cache.accounts[string(addr)] = acc
}
func (cache *AccountCache) Sync() {
// MUST BE DETERMINISTIC
// First, order the addrs.
addrs := []string{}
for addr := range cache.accounts {
addrs = append(addrs, string(addr))
}
sort.Strings(addrs)
// Set the accounts in order.
for _, addr := range addrs {
cache.state.SetAccount([]byte(addr), cache.accounts[addr])
}
}

View File

@ -2,7 +2,6 @@ package state
import (
"bytes"
"strings"
"github.com/tendermint/basecoin/types"
. "github.com/tendermint/go-common"
@ -94,9 +93,8 @@ func ExecTx(state *State, tx types.Tx, isCheckTx bool, evc events.Fireable) tmsp
}
// Validate call address
if strings.HasPrefix(string(tx.Address), "gov/") {
// This is a gov call.
} else {
plugin := state.GetPlugin(tx.Address)
if plugin != nil {
return tmsp.ErrBaseUnknownAddress.AppendLog(Fmt("Unrecognized address %X", tx.Address))
}
@ -105,16 +103,21 @@ func ExecTx(state *State, tx types.Tx, isCheckTx bool, evc events.Fireable) tmsp
inAcc.Sequence += 1
inAcc.Balance -= tx.Input.Amount
state.SetCheckAccount(tx.Input.Address, inAcc.Sequence, inAcc.Balance)
inAccCopy := inAcc.Copy()
// If this is AppendTx, actually save accounts
if !isCheckTx {
state.SetAccount(tx.Input.Address, inAcc)
// NOTE: value is dangling.
// XXX: don't just give it back
inAcc.Balance += value
// TODO: logic.
// TODO: persist
// state.SetAccount(tx.Input.Address, inAcc)
if isCheckTx {
return tmsp.OK
}
// Run the tx.
cache := NewAccountCache(state)
cache.SetAccount(tx.Input.Address, inAcc)
gas := int64(1) // TODO
ctx := types.NewCallContext(cache, inAcc, value, &gas)
res = plugin.CallTx(ctx, tx.Data)
if res.IsOK() {
cache.Sync()
log.Info("Successful execution")
// Fire events
/*
@ -127,9 +130,14 @@ func ExecTx(state *State, tx types.Tx, isCheckTx bool, evc events.Fireable) tmsp
evc.FireEvent(types.EventStringAccOutput(tx.Address), types.EventDataTx{tx, ret, exception})
}
*/
} else {
log.Info("CallTx failed", "error", res)
// Just return the value and return.
// TODO: return gas?
inAccCopy.Balance += value
state.SetAccount(tx.Input.Address, inAccCopy)
}
return tmsp.OK
return res
default:
return tmsp.ErrBaseEncodingError.SetLog("Unknown tx type")

View File

@ -11,6 +11,7 @@ type State struct {
chainID string
eyesCli *eyes.Client
checkCache map[string]checkAccount
plugins map[string]types.Plugin
LastBlockHeight uint64
LastBlockHash []byte
@ -37,6 +38,14 @@ func (s *State) GetChainID() string {
return s.chainID
}
func (s *State) RegisterPlugin(addr []byte, plugin types.Plugin) {
s.plugins[string(addr)] = plugin
}
func (s *State) GetPlugin(addr []byte) types.Plugin {
return s.plugins[string(addr)]
}
//----------------------------------------
// CheckTx state

View File

@ -40,5 +40,11 @@ type AccountGetter interface {
type AccountGetterSetter interface {
GetAccount(addr []byte) *Account
SetAccount(acc *Account)
SetAccount(addr []byte, acc *Account)
}
type AccountCacher interface {
GetAccount(addr []byte) *Account
SetAccount(addr []byte, acc *Account)
Sync()
}

View File

@ -1,6 +0,0 @@
package types
type Plugin func(ags AccountGetterSetter,
caller *Account,
input []byte,
gas *int64) (result []byte, err error)

28
types/plugin.go Normal file
View File

@ -0,0 +1,28 @@
package types
import (
tmsp "github.com/tendermint/tmsp/types"
)
// Value is any floating value. It must be given to someone.
// Gas is a pointer to remainig gas. Decrement as you go,
// if any gas is left the user is
type Plugin interface {
CallTx(ctx CallContext, txBytes []byte) tmsp.Result
}
type CallContext struct {
Cache AccountCacher
Caller *Account
Value int64
Gas *int64
}
func NewCallContext(cache AccountCacher, caller *Account, value int64, gas *int64) CallContext {
return CallContext{
Cache: cache,
Caller: caller,
Value: value,
Gas: gas,
}
}