Raw File
tx_filter.go
package state

import (
	"sync"
	"time"

	abci "github.com/tendermint/tendermint/abci/types"
	"github.com/tendermint/tendermint/internal/mempool"
	"github.com/tendermint/tendermint/types"
)

func cachingStateFetcher(store Store) func() (State, error) {
	const ttl = time.Second

	var (
		last  time.Time
		mutex = &sync.Mutex{}
		cache State
		err   error
	)

	return func() (State, error) {
		mutex.Lock()
		defer mutex.Unlock()

		if time.Since(last) < ttl && cache.ChainID != "" {
			return cache, nil
		}

		cache, err = store.Load()
		if err != nil {
			return State{}, err
		}
		last = time.Now()

		return cache, nil
	}

}

// TxPreCheckFromStore returns a function to filter transactions before processing.
// The function limits the size of a transaction to the block's maximum data size.
func TxPreCheckFromStore(store Store) mempool.PreCheckFunc {
	fetch := cachingStateFetcher(store)

	return func(tx types.Tx) error {
		state, err := fetch()
		if err != nil {
			return err
		}

		return TxPreCheckForState(state)(tx)
	}
}

func TxPreCheckForState(state State) mempool.PreCheckFunc {
	return func(tx types.Tx) error {
		maxDataBytes := types.MaxDataBytesNoEvidence(
			state.ConsensusParams.Block.MaxBytes,
			state.Validators.Size(),
		)
		return mempool.PreCheckMaxBytes(maxDataBytes)(tx)
	}

}

// TxPostCheckFromStore returns a function to filter transactions after processing.
// The function limits the gas wanted by a transaction to the block's maximum total gas.
func TxPostCheckFromStore(store Store) mempool.PostCheckFunc {
	fetch := cachingStateFetcher(store)

	return func(tx types.Tx, resp *abci.ResponseCheckTx) error {
		state, err := fetch()
		if err != nil {
			return err
		}
		return mempool.PostCheckMaxGas(state.ConsensusParams.Block.MaxGas)(tx, resp)
	}
}

func TxPostCheckForState(state State) mempool.PostCheckFunc {
	return func(tx types.Tx, resp *abci.ResponseCheckTx) error {
		return mempool.PostCheckMaxGas(state.ConsensusParams.Block.MaxGas)(tx, resp)
	}
}
back to top