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 {
|
func NewBasecoin(eyesCli *eyes.Client) *Basecoin {
|
||||||
|
state_ := state.NewState(eyesCli)
|
||||||
govMint := gov.NewGovernmint(eyesCli)
|
govMint := gov.NewGovernmint(eyesCli)
|
||||||
|
state_.RegisterPlugin([]byte("gov"), govMint)
|
||||||
return &Basecoin{
|
return &Basecoin{
|
||||||
eyesCli: eyesCli,
|
eyesCli: eyesCli,
|
||||||
govMint: govMint,
|
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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/tendermint/basecoin/types"
|
"github.com/tendermint/basecoin/types"
|
||||||
. "github.com/tendermint/go-common"
|
. "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
|
// Validate call address
|
||||||
if strings.HasPrefix(string(tx.Address), "gov/") {
|
plugin := state.GetPlugin(tx.Address)
|
||||||
// This is a gov call.
|
if plugin != nil {
|
||||||
} else {
|
|
||||||
return tmsp.ErrBaseUnknownAddress.AppendLog(Fmt("Unrecognized address %X", tx.Address))
|
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.Sequence += 1
|
||||||
inAcc.Balance -= tx.Input.Amount
|
inAcc.Balance -= tx.Input.Amount
|
||||||
state.SetCheckAccount(tx.Input.Address, inAcc.Sequence, inAcc.Balance)
|
state.SetCheckAccount(tx.Input.Address, inAcc.Sequence, inAcc.Balance)
|
||||||
|
inAccCopy := inAcc.Copy()
|
||||||
|
|
||||||
// If this is AppendTx, actually save accounts
|
// If this is AppendTx, actually save accounts
|
||||||
if !isCheckTx {
|
if isCheckTx {
|
||||||
state.SetAccount(tx.Input.Address, inAcc)
|
return tmsp.OK
|
||||||
// NOTE: value is dangling.
|
}
|
||||||
// XXX: don't just give it back
|
|
||||||
inAcc.Balance += value
|
// Run the tx.
|
||||||
// TODO: logic.
|
cache := NewAccountCache(state)
|
||||||
// TODO: persist
|
cache.SetAccount(tx.Input.Address, inAcc)
|
||||||
// state.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")
|
log.Info("Successful execution")
|
||||||
// Fire events
|
// 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})
|
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 res
|
||||||
return tmsp.OK
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return tmsp.ErrBaseEncodingError.SetLog("Unknown tx type")
|
return tmsp.ErrBaseEncodingError.SetLog("Unknown tx type")
|
||||||
|
|
|
@ -11,6 +11,7 @@ type State struct {
|
||||||
chainID string
|
chainID string
|
||||||
eyesCli *eyes.Client
|
eyesCli *eyes.Client
|
||||||
checkCache map[string]checkAccount
|
checkCache map[string]checkAccount
|
||||||
|
plugins map[string]types.Plugin
|
||||||
|
|
||||||
LastBlockHeight uint64
|
LastBlockHeight uint64
|
||||||
LastBlockHash []byte
|
LastBlockHash []byte
|
||||||
|
@ -37,6 +38,14 @@ func (s *State) GetChainID() string {
|
||||||
return s.chainID
|
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
|
// CheckTx state
|
||||||
|
|
||||||
|
|
|
@ -40,5 +40,11 @@ type AccountGetter interface {
|
||||||
|
|
||||||
type AccountGetterSetter interface {
|
type AccountGetterSetter interface {
|
||||||
GetAccount(addr []byte) *Account
|
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