From 405720b218c74ec730541cdcb360db54deb75474 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 24 Apr 2015 17:45:51 +0200 Subject: [PATCH] xeth, core, cmd/utils: Transaction can not be over block gas limit Transactions will be invalidated when the tx.gas_limit > block.gas_limit --- cmd/utils/flags.go | 2 +- core/chain_makers.go | 2 +- core/chain_manager.go | 29 ++++++++++++++++++----------- core/chain_manager_test.go | 4 ++-- core/transaction_pool.go | 10 +++++++++- core/transaction_pool_test.go | 2 +- eth/backend.go | 2 +- xeth/xeth.go | 4 ++++ 8 files changed, 37 insertions(+), 18 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index b8f3982e2..a75663a4c 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -317,7 +317,7 @@ func GetChain(ctx *cli.Context) (*core.ChainManager, common.Database, common.Dat eventMux := new(event.TypeMux) chainManager := core.NewChainManager(blockDb, stateDb, eventMux) pow := ethash.New(chainManager) - txPool := core.NewTxPool(eventMux, chainManager.State) + txPool := core.NewTxPool(eventMux, chainManager.State, chainManager.GasLimit) blockProcessor := core.NewBlockProcessor(stateDb, extraDb, pow, txPool, chainManager, eventMux) chainManager.SetProcessor(blockProcessor) diff --git a/core/chain_makers.go b/core/chain_makers.go index 9b4911fba..e7a65748e 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -124,7 +124,7 @@ func newChainManager(block *types.Block, eventMux *event.TypeMux, db common.Data // block processor with fake pow func newBlockProcessor(db common.Database, cman *ChainManager, eventMux *event.TypeMux) *BlockProcessor { chainMan := newChainManager(nil, eventMux, db) - txpool := NewTxPool(eventMux, chainMan.State) + txpool := NewTxPool(eventMux, chainMan.State, chainMan.GasLimit) bman := NewBlockProcessor(db, db, FakePow{}, txpool, chainMan, eventMux) return bman } diff --git a/core/chain_manager.go b/core/chain_manager.go index a09b2e63b..bfe156262 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -78,11 +78,12 @@ type ChainManager struct { eventMux *event.TypeMux genesisBlock *types.Block // Last known total difficulty - mu sync.RWMutex - tsmu sync.RWMutex - td *big.Int - currentBlock *types.Block - lastBlockHash common.Hash + mu sync.RWMutex + tsmu sync.RWMutex + td *big.Int + currentBlock *types.Block + lastBlockHash common.Hash + currentGasLimit *big.Int transState *state.StateDB txState *state.ManagedState @@ -95,12 +96,13 @@ type ChainManager struct { func NewChainManager(blockDb, stateDb common.Database, mux *event.TypeMux) *ChainManager { bc := &ChainManager{ - blockDb: blockDb, - stateDb: stateDb, - genesisBlock: GenesisBlock(stateDb), - eventMux: mux, - quit: make(chan struct{}), - cache: NewBlockCache(blockCacheLimit), + blockDb: blockDb, + stateDb: stateDb, + genesisBlock: GenesisBlock(stateDb), + eventMux: mux, + quit: make(chan struct{}), + cache: NewBlockCache(blockCacheLimit), + currentGasLimit: new(big.Int), } bc.setLastBlock() @@ -157,6 +159,10 @@ func (self *ChainManager) Td() *big.Int { return self.td } +func (self *ChainManager) GasLimit() *big.Int { + return self.currentGasLimit +} + func (self *ChainManager) LastBlockHash() common.Hash { self.mu.RLock() defer self.mu.RUnlock() @@ -652,6 +658,7 @@ out: // We need some control over the mining operation. Acquiring locks and waiting for the miner to create new block takes too long // and in most cases isn't even necessary. if i+1 == ev.canonicalCount { + self.currentGasLimit = CalcGasLimit(self.GetBlock(event.Block.ParentHash()), event.Block) self.eventMux.Post(ChainHeadEvent{event.Block}) } case ChainSplitEvent: diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index f16c0f0c3..c2911150a 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -256,7 +256,7 @@ func TestChainInsertions(t *testing.T) { var eventMux event.TypeMux chainMan := NewChainManager(db, db, &eventMux) - txPool := NewTxPool(&eventMux, chainMan.State) + txPool := NewTxPool(&eventMux, chainMan.State, func() *big.Int { return big.NewInt(100000000) }) blockMan := NewBlockProcessor(db, db, nil, txPool, chainMan, &eventMux) chainMan.SetProcessor(blockMan) @@ -302,7 +302,7 @@ func TestChainMultipleInsertions(t *testing.T) { } var eventMux event.TypeMux chainMan := NewChainManager(db, db, &eventMux) - txPool := NewTxPool(&eventMux, chainMan.State) + txPool := NewTxPool(&eventMux, chainMan.State, func() *big.Int { return big.NewInt(100000000) }) blockMan := NewBlockProcessor(db, db, nil, txPool, chainMan, &eventMux) chainMan.SetProcessor(blockMan) done := make(chan bool, max) diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 392e17856..f6414a882 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -23,6 +23,7 @@ var ( ErrNonExistentAccount = errors.New("Account does not exist") ErrInsufficientFunds = errors.New("Insufficient funds") ErrIntrinsicGas = errors.New("Intrinsic gas too low") + ErrGasLimit = errors.New("Exceeds block gas limit") ) const txPoolQueueSize = 50 @@ -52,6 +53,8 @@ type TxPool struct { quit chan bool // The state function which will allow us to do some pre checkes currentState stateFn + // The current gas limit function callback + gasLimit func() *big.Int // The actual pool txs map[common.Hash]*types.Transaction invalidHashes *set.Set @@ -63,7 +66,7 @@ type TxPool struct { eventMux *event.TypeMux } -func NewTxPool(eventMux *event.TypeMux, currentStateFn stateFn) *TxPool { +func NewTxPool(eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool { txPool := &TxPool{ txs: make(map[common.Hash]*types.Transaction), queue: make(map[common.Address]types.Transactions), @@ -72,6 +75,7 @@ func NewTxPool(eventMux *event.TypeMux, currentStateFn stateFn) *TxPool { eventMux: eventMux, invalidHashes: set.New(), currentState: currentStateFn, + gasLimit: gasLimitFn, } return txPool } @@ -116,6 +120,10 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { return ErrNonExistentAccount } + if pool.gasLimit().Cmp(tx.GasLimit) < 0 { + return ErrGasLimit + } + if pool.currentState().GetBalance(from).Cmp(new(big.Int).Mul(tx.Price, tx.GasLimit)) < 0 { return ErrInsufficientFunds } diff --git a/core/transaction_pool_test.go b/core/transaction_pool_test.go index 0e049139e..f96d2b651 100644 --- a/core/transaction_pool_test.go +++ b/core/transaction_pool_test.go @@ -23,7 +23,7 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { var m event.TypeMux key, _ := crypto.GenerateKey() - return NewTxPool(&m, func() *state.StateDB { return statedb }), key + return NewTxPool(&m, func() *state.StateDB { return statedb }, func() *big.Int { return big.NewInt(1000000) }), key } func TestInvalidTransactions(t *testing.T) { diff --git a/eth/backend.go b/eth/backend.go index d0a56de1c..ebc95c752 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -219,7 +219,7 @@ func New(config *Config) (*Ethereum, error) { eth.chainManager = core.NewChainManager(blockDb, stateDb, eth.EventMux()) eth.downloader = downloader.New(eth.chainManager.HasBlock, eth.chainManager.InsertChain) eth.pow = ethash.New(eth.chainManager) - eth.txPool = core.NewTxPool(eth.EventMux(), eth.chainManager.State) + eth.txPool = core.NewTxPool(eth.EventMux(), eth.chainManager.State, eth.chainManager.GasLimit) eth.blockProcessor = core.NewBlockProcessor(stateDb, extraDb, eth.pow, eth.txPool, eth.chainManager, eth.EventMux()) eth.chainManager.SetProcessor(eth.blockProcessor) eth.whisper = whisper.New() diff --git a/xeth/xeth.go b/xeth/xeth.go index 251b070e4..693acb910 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -236,6 +236,10 @@ func (self *XEth) CurrentBlock() *types.Block { return self.backend.ChainManager().CurrentBlock() } +func (self *XEth) GasLimit() *big.Int { + return self.backend.ChainManager().GasLimit() +} + func (self *XEth) Block(v interface{}) *Block { if n, ok := v.(int32); ok { return self.BlockByNumber(int64(n))