Fix Basecoin CheckTx cache
This commit is contained in:
parent
615981c70d
commit
13a0bdd911
|
@ -159,10 +159,17 @@ func (app *Basecoin) InitChain(validators []*tmsp.Validator) {
|
|||
app.govMint.InitChain(validators)
|
||||
}
|
||||
|
||||
// TMSP::BeginBlock
|
||||
func (app *Basecoin) BeginBlock(height uint64) {
|
||||
// app.govMint.BeginBlock(height)
|
||||
// TODO other plugins?
|
||||
}
|
||||
|
||||
// TMSP::EndBlock
|
||||
func (app *Basecoin) EndBlock(height uint64) []*tmsp.Validator {
|
||||
app.state.ResetCacheState()
|
||||
return app.govMint.EndBlock(height)
|
||||
// TODO other plugins?
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
|
|
@ -10,10 +10,20 @@ import (
|
|||
)
|
||||
|
||||
// If the tx is invalid, a TMSP error will be returned.
|
||||
func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc events.Fireable) tmsp.Result {
|
||||
func ExecTx(s *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc events.Fireable) tmsp.Result {
|
||||
|
||||
// TODO: do something with fees
|
||||
fees := int64(0)
|
||||
chainID := s.GetChainID()
|
||||
|
||||
// Get the state. If isCheckTx, then we use a cache.
|
||||
// The idea is to throw away this cache after every EndBlock().
|
||||
var state types.AccountGetterSetter
|
||||
if isCheckTx {
|
||||
state = s.GetCheckCache()
|
||||
} else {
|
||||
state = s
|
||||
}
|
||||
|
||||
// Exec tx
|
||||
switch tx := tx.(type) {
|
||||
|
@ -31,8 +41,8 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e
|
|||
}
|
||||
|
||||
// Validate inputs and outputs
|
||||
signBytes := tx.SignBytes(state.GetChainID())
|
||||
inTotal, res := validateInputs(state, accounts, signBytes, tx.Inputs)
|
||||
signBytes := tx.SignBytes(chainID)
|
||||
inTotal, res := validateInputs(accounts, signBytes, tx.Inputs)
|
||||
if res.IsErr() {
|
||||
return res.PrependLog("in validateInputs()")
|
||||
}
|
||||
|
@ -49,7 +59,7 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e
|
|||
// TODO: Fee validation for SendTx
|
||||
|
||||
// Good! Adjust accounts
|
||||
adjustByInputs(state, accounts, tx.Inputs, isCheckTx)
|
||||
adjustByInputs(state, accounts, tx.Inputs)
|
||||
adjustByOutputs(state, accounts, tx.Outputs, isCheckTx)
|
||||
|
||||
/*
|
||||
|
@ -81,8 +91,8 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e
|
|||
log.Info(Fmt("Can't find pubkey for %X", tx.Input.Address))
|
||||
return res
|
||||
}
|
||||
signBytes := tx.SignBytes(state.GetChainID())
|
||||
res := validateInput(state, inAcc, signBytes, tx.Input)
|
||||
signBytes := tx.SignBytes(chainID)
|
||||
res := validateInput(inAcc, signBytes, tx.Input)
|
||||
if res.IsErr() {
|
||||
log.Info(Fmt("validateInput failed on %X: %v", tx.Input.Address, res))
|
||||
return res.PrependLog("in validateInput()")
|
||||
|
@ -103,16 +113,18 @@ func ExecTx(state *State, pgz *types.Plugins, tx types.Tx, isCheckTx bool, evc e
|
|||
value := tx.Input.Amount - tx.Fee
|
||||
inAcc.Sequence += 1
|
||||
inAcc.Balance -= tx.Input.Amount
|
||||
state.SetCheckAccount(tx.Input.Address, inAcc.Sequence, inAcc.Balance)
|
||||
inAccCopy := inAcc.Copy()
|
||||
|
||||
// If this is a CheckTx, stop now.
|
||||
if isCheckTx {
|
||||
state.SetAccount(tx.Input.Address, inAcc)
|
||||
return tmsp.OK
|
||||
}
|
||||
|
||||
// Create inAcc checkpoint
|
||||
inAccCopy := inAcc.Copy()
|
||||
|
||||
// Run the tx.
|
||||
cache := NewAccountCache(state)
|
||||
cache := types.NewAccountCache(state)
|
||||
cache.SetAccount(tx.Input.Address, inAcc)
|
||||
gas := int64(1) // TODO
|
||||
ctx := types.NewCallContext(cache, inAcc, value, &gas)
|
||||
|
@ -218,14 +230,14 @@ func checkInputPubKey(address []byte, acc *types.Account, in types.TxInput) tmsp
|
|||
}
|
||||
|
||||
// Validate inputs and compute total amount
|
||||
func validateInputs(state *State, accounts map[string]*types.Account, signBytes []byte, ins []types.TxInput) (total int64, res tmsp.Result) {
|
||||
func validateInputs(accounts map[string]*types.Account, signBytes []byte, ins []types.TxInput) (total int64, res tmsp.Result) {
|
||||
|
||||
for _, in := range ins {
|
||||
acc := accounts[string(in.Address)]
|
||||
if acc == nil {
|
||||
PanicSanity("validateInputs() expects account in accounts")
|
||||
}
|
||||
res = validateInput(state, acc, signBytes, in)
|
||||
res = validateInput(acc, signBytes, in)
|
||||
if res.IsErr() {
|
||||
return
|
||||
}
|
||||
|
@ -235,13 +247,13 @@ func validateInputs(state *State, accounts map[string]*types.Account, signBytes
|
|||
return total, tmsp.OK
|
||||
}
|
||||
|
||||
func validateInput(state *State, acc *types.Account, signBytes []byte, in types.TxInput) (res tmsp.Result) {
|
||||
func validateInput(acc *types.Account, signBytes []byte, in types.TxInput) (res tmsp.Result) {
|
||||
// Check TxInput basic
|
||||
if res := in.ValidateBasic(); res.IsErr() {
|
||||
return res
|
||||
}
|
||||
// Check sequence/balance
|
||||
seq, balance := state.GetCheckAccount(in.Address, acc.Sequence, acc.Balance)
|
||||
seq, balance := acc.Sequence, acc.Balance
|
||||
if seq+1 != in.Sequence {
|
||||
return tmsp.ErrBaseInvalidSequence.AppendLog(Fmt("Got %v, expected %v. (acc.seq=%v)", in.Sequence, seq+1, acc.Sequence))
|
||||
}
|
||||
|
@ -268,7 +280,7 @@ func validateOutputs(outs []types.TxOutput) (total int64, res tmsp.Result) {
|
|||
return total, tmsp.OK
|
||||
}
|
||||
|
||||
func adjustByInputs(state *State, accounts map[string]*types.Account, ins []types.TxInput, isCheckTx bool) {
|
||||
func adjustByInputs(state types.AccountSetter, accounts map[string]*types.Account, ins []types.TxInput) {
|
||||
for _, in := range ins {
|
||||
acc := accounts[string(in.Address)]
|
||||
if acc == nil {
|
||||
|
@ -279,15 +291,11 @@ func adjustByInputs(state *State, accounts map[string]*types.Account, ins []type
|
|||
}
|
||||
acc.Balance -= in.Amount
|
||||
acc.Sequence += 1
|
||||
state.SetCheckAccount(in.Address, acc.Sequence, acc.Balance)
|
||||
if !isCheckTx {
|
||||
// NOTE: Must be set in deterministic order
|
||||
state.SetAccount(in.Address, acc)
|
||||
}
|
||||
state.SetAccount(in.Address, acc)
|
||||
}
|
||||
}
|
||||
|
||||
func adjustByOutputs(state *State, accounts map[string]*types.Account, outs []types.TxOutput, isCheckTx bool) {
|
||||
func adjustByOutputs(state types.AccountSetter, accounts map[string]*types.Account, outs []types.TxOutput, isCheckTx bool) {
|
||||
for _, out := range outs {
|
||||
acc := accounts[string(out.Address)]
|
||||
if acc == nil {
|
||||
|
@ -295,8 +303,6 @@ func adjustByOutputs(state *State, accounts map[string]*types.Account, outs []ty
|
|||
}
|
||||
acc.Balance += out.Amount
|
||||
if !isCheckTx {
|
||||
state.SetCheckAccount(out.Address, acc.Sequence, acc.Balance)
|
||||
// NOTE: Must be set in deterministic order
|
||||
state.SetAccount(out.Address, acc)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
type State struct {
|
||||
chainID string
|
||||
eyesCli *eyes.Client
|
||||
checkCache map[string]checkAccount
|
||||
checkCache *types.AccountCache
|
||||
|
||||
LastBlockHeight uint64
|
||||
LastBlockHash []byte
|
||||
|
@ -19,10 +19,10 @@ type State struct {
|
|||
|
||||
func NewState(eyesCli *eyes.Client) *State {
|
||||
s := &State{
|
||||
chainID: "",
|
||||
eyesCli: eyesCli,
|
||||
checkCache: make(map[string]checkAccount),
|
||||
chainID: "",
|
||||
eyesCli: eyesCli,
|
||||
}
|
||||
s.checkCache = types.NewAccountCache(s)
|
||||
return s
|
||||
}
|
||||
|
||||
|
@ -37,32 +37,6 @@ func (s *State) GetChainID() string {
|
|||
return s.chainID
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// CheckTx state
|
||||
|
||||
type checkAccount struct {
|
||||
sequence int
|
||||
balance int64
|
||||
}
|
||||
|
||||
func (s *State) GetCheckAccount(addr []byte, defaultSequence int, defaultBalance int64) (sequence int, balance int64) {
|
||||
cAcc, ok := s.checkCache[string(addr)]
|
||||
if !ok {
|
||||
return defaultSequence, defaultBalance
|
||||
}
|
||||
return cAcc.sequence, cAcc.balance
|
||||
}
|
||||
|
||||
func (s *State) SetCheckAccount(addr []byte, sequence int, balance int64) {
|
||||
s.checkCache[string(addr)] = checkAccount{sequence, balance}
|
||||
}
|
||||
|
||||
func (s *State) ResetCacheState() {
|
||||
s.checkCache = make(map[string]checkAccount)
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
func (s *State) GetAccount(addr []byte) *types.Account {
|
||||
res := s.eyesCli.GetSync(addr)
|
||||
if res.IsErr() {
|
||||
|
@ -86,3 +60,11 @@ func (s *State) SetAccount(address []byte, acc *types.Account) {
|
|||
panic(Fmt("Error storing account addr %X error: %v", address, res.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) GetCheckCache() *types.AccountCache {
|
||||
return s.checkCache
|
||||
}
|
||||
|
||||
func (s *State) ResetCacheState() {
|
||||
s.checkCache = types.NewAccountCache(s)
|
||||
}
|
||||
|
|
|
@ -129,16 +129,18 @@ func testSequence() {
|
|||
signBytes := tx.SignBytes(chainID)
|
||||
sig := root.PrivKey.Sign(signBytes)
|
||||
tx.Inputs[0].Signature = sig
|
||||
//fmt.Println("tx:", tx)
|
||||
// fmt.Printf("ADDR: %X -> %X\n", tx.Inputs[0].Address, tx.Outputs[0].Address)
|
||||
|
||||
// Write request
|
||||
txBytes := wire.BinaryBytes(tx)
|
||||
res := bcApp.CheckTx(txBytes)
|
||||
res := bcApp.AppendTx(txBytes)
|
||||
if res.IsErr() {
|
||||
Exit("AppendTx error: " + res.Error())
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("-------------------- RANDOM SENDS --------------------")
|
||||
|
||||
// Now send coins between these accounts
|
||||
for {
|
||||
randA := RandInt() % len(privAccounts)
|
||||
|
@ -173,7 +175,7 @@ func testSequence() {
|
|||
signBytes := tx.SignBytes(chainID)
|
||||
sig := privAccountA.PrivKey.Sign(signBytes)
|
||||
tx.Inputs[0].Signature = sig
|
||||
//fmt.Println("tx:", tx)
|
||||
// fmt.Printf("ADDR: %X -> %X\n", tx.Inputs[0].Address, tx.Outputs[0].Address)
|
||||
|
||||
// Write request
|
||||
txBytes := wire.BinaryBytes(tx)
|
||||
|
|
|
@ -38,13 +38,11 @@ type AccountGetter interface {
|
|||
GetAccount(addr []byte) *Account
|
||||
}
|
||||
|
||||
type AccountSetter interface {
|
||||
SetAccount(addr []byte, acc *Account)
|
||||
}
|
||||
|
||||
type AccountGetterSetter interface {
|
||||
GetAccount(addr []byte) *Account
|
||||
SetAccount(addr []byte, acc *Account)
|
||||
}
|
||||
|
||||
type AccountCacher interface {
|
||||
GetAccount(addr []byte) *Account
|
||||
SetAccount(addr []byte, acc *Account)
|
||||
Sync()
|
||||
}
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
package state
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/tendermint/basecoin/types"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type AccountCache struct {
|
||||
state *State
|
||||
accounts map[string]*types.Account
|
||||
state AccountGetterSetter
|
||||
accounts map[string]*Account
|
||||
}
|
||||
|
||||
func NewAccountCache(state *State) *AccountCache {
|
||||
func NewAccountCache(state AccountGetterSetter) *AccountCache {
|
||||
return &AccountCache{
|
||||
state: state,
|
||||
accounts: make(map[string]*types.Account),
|
||||
accounts: make(map[string]*Account),
|
||||
}
|
||||
}
|
||||
|
||||
func (cache *AccountCache) GetAccount(addr []byte) *types.Account {
|
||||
func (cache *AccountCache) GetAccount(addr []byte) *Account {
|
||||
acc, ok := cache.accounts[string(addr)]
|
||||
if !ok {
|
||||
acc = cache.state.GetAccount(addr)
|
||||
|
@ -26,7 +25,7 @@ func (cache *AccountCache) GetAccount(addr []byte) *types.Account {
|
|||
return acc
|
||||
}
|
||||
|
||||
func (cache *AccountCache) SetAccount(addr []byte, acc *types.Account) {
|
||||
func (cache *AccountCache) SetAccount(addr []byte, acc *Account) {
|
||||
cache.accounts[string(addr)] = acc
|
||||
}
|
||||
|
||||
|
@ -43,4 +42,16 @@ func (cache *AccountCache) Sync() {
|
|||
for _, addr := range addrs {
|
||||
cache.state.SetAccount([]byte(addr), cache.accounts[addr])
|
||||
}
|
||||
|
||||
// Reset accounts
|
||||
cache.accounts = make(map[string]*Account)
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
|
||||
// NOT USED
|
||||
type AccountCacher interface {
|
||||
GetAccount(addr []byte) *Account
|
||||
SetAccount(addr []byte, acc *Account)
|
||||
Sync()
|
||||
}
|
Loading…
Reference in New Issue