Plugins and AccountCaches
This commit is contained in:
parent
83e7c9dab1
commit
964a4cfd50
|
@ -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_,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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])
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
package types
|
||||
|
||||
type Plugin func(ags AccountGetterSetter,
|
||||
caller *Account,
|
||||
input []byte,
|
||||
gas *int64) (result []byte, err error)
|
|
@ -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,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue