code.vegaprotocol.io/vega@v0.79.0/core/blockchain/abci/app.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package abci
    17  
    18  import (
    19  	"context"
    20  
    21  	"code.vegaprotocol.io/vega/core/blockchain"
    22  	"code.vegaprotocol.io/vega/core/txn"
    23  	"code.vegaprotocol.io/vega/core/types"
    24  
    25  	abci "github.com/cometbft/cometbft/abci/types"
    26  	lru "github.com/hashicorp/golang-lru"
    27  )
    28  
    29  type (
    30  	Command   byte
    31  	TxHandler func(ctx context.Context, tx Tx) error
    32  )
    33  
    34  type SnapshotEngine interface {
    35  	AddProviders(provs ...types.StateProvider)
    36  }
    37  
    38  type App struct {
    39  	abci.BaseApplication
    40  	codec Codec
    41  
    42  	// handlers
    43  	OnPrepareProposal PrepareProposalHandler
    44  	OnProcessProposal ProcessProposalHandler
    45  	OnInitChain       OnInitChainHandler
    46  	OnCheckTx         OnCheckTxHandler
    47  	OnCommit          OnCommitHandler
    48  	OnBeginBlock      OnBeginBlockHandler
    49  	OnEndBlock        OnEndBlockHandler
    50  	OnFinalize        FinalizeHandler
    51  
    52  	// spam check
    53  	OnCheckTxSpam OnCheckTxSpamHandler
    54  
    55  	// snapshot stuff
    56  
    57  	OnListSnapshots      ListSnapshotsHandler
    58  	OnOfferSnapshot      OfferSnapshotHandler
    59  	OnLoadSnapshotChunk  LoadSnapshotChunkHandler
    60  	OnApplySnapshotChunk ApplySnapshotChunkHandler
    61  	OnInfo               InfoHandler
    62  
    63  	// These are Tx handlers
    64  	checkTxs   map[txn.Command]TxHandler
    65  	deliverTxs map[txn.Command]TxHandler
    66  
    67  	// checkedTxs holds a map of valid transactions (validated by CheckTx)
    68  	// They are consumed by DeliverTx to avoid double validation.
    69  	checkedTxs *lru.Cache // map[string]Transaction
    70  
    71  	// the current block context
    72  	ctx context.Context
    73  
    74  	chainID string
    75  }
    76  
    77  func New(codec Codec) *App {
    78  	lruCache, _ := lru.New(1024)
    79  	return &App{
    80  		codec:      codec,
    81  		checkTxs:   map[txn.Command]TxHandler{},
    82  		deliverTxs: map[txn.Command]TxHandler{},
    83  		checkedTxs: lruCache,
    84  		ctx:        context.Background(),
    85  	}
    86  }
    87  
    88  func (app *App) SetChainID(chainID string) {
    89  	app.chainID = chainID
    90  }
    91  
    92  func (app *App) GetChainID() string {
    93  	return app.chainID
    94  }
    95  
    96  func (app *App) HandleCheckTx(cmd txn.Command, fn TxHandler) *App {
    97  	app.checkTxs[cmd] = fn
    98  	return app
    99  }
   100  
   101  func (app *App) HandleDeliverTx(cmd txn.Command, fn TxHandler) *App {
   102  	app.deliverTxs[cmd] = fn
   103  	return app
   104  }
   105  
   106  func (app *App) decodeTx(bytes []byte) (Tx, uint32, error) {
   107  	tx, err := app.codec.Decode(bytes, app.chainID)
   108  	if err != nil {
   109  		return nil, blockchain.AbciTxnDecodingFailure, err
   110  	}
   111  	return tx, 0, nil
   112  }
   113  
   114  // cacheTx adds a Tx to the cache.
   115  func (app *App) cacheTx(in []byte, tx Tx) {
   116  	app.checkedTxs.Add(string(in), tx)
   117  }
   118  
   119  // txFromCache retrieves (and remove if found) a Tx from the cache,
   120  // it returns the Tx or nil if not found.
   121  func (app *App) txFromCache(in []byte) Tx {
   122  	tx, ok := app.checkedTxs.Get(string(in))
   123  	if !ok {
   124  		return nil
   125  	}
   126  
   127  	return tx.(Tx)
   128  }
   129  
   130  func (app *App) removeTxFromCache(in []byte) {
   131  	app.checkedTxs.Remove(string(in))
   132  }
   133  
   134  // getTx returns an internal Tx given a []byte.
   135  // An error code different from 0 is returned if decoding  fails with its the corresponding error.
   136  func (app *App) getTx(bytes []byte) (Tx, uint32, error) {
   137  	if tx := app.txFromCache(bytes); tx != nil {
   138  		return tx, 0, nil
   139  	}
   140  
   141  	tx, code, err := app.decodeTx(bytes)
   142  	if err != nil {
   143  		return nil, code, err
   144  	}
   145  
   146  	return tx, 0, nil
   147  }