diff --git a/core/tx_pool.go b/core/tx_pool.go index cba15d06c5..8cae8434e4 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -215,7 +215,8 @@ type TxPool struct { wg sync.WaitGroup // for shutdown sync - homestead bool + homestead bool + IsMasterNode func(address common.Address) bool } // NewTxPool creates a new transaction pool to gather, sort and filter inbound @@ -593,8 +594,10 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { } // Drop non-local transactions under our own minimal accepted gas price local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network - if !local && tx.To() != nil && !tx.IsSpecialTransaction() && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { - return ErrUnderpriced + if !local && tx.To() != nil && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { + if !tx.IsSpecialTransaction() || (pool.IsMasterNode != nil && !pool.IsMasterNode(from)) { + return ErrUnderpriced + } } // Ensure the transaction adheres to nonce ordering if pool.currentState.GetNonce(from) > tx.Nonce() { @@ -650,6 +653,10 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { invalidTxCounter.Inc(1) return false, err } + from, _ := types.Sender(pool.signer, tx) // already validated + if tx.IsSpecialTransaction() && pool.IsMasterNode != nil && pool.IsMasterNode(from) { + return pool.promoteSpecialTx(from, tx) + } // If the transaction pool is full, discard underpriced transactions if uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue { // If the new transaction is underpriced, don't accept it @@ -666,10 +673,6 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { pool.removeTx(tx.Hash()) } } - from, _ := types.Sender(pool.signer, tx) // already validated - if tx.IsSpecialTransaction() { - return pool.promoteSpecialTx(from, tx) - } // If the transaction is replacing an already pending one, do directly if list := pool.pending[from]; list != nil && list.Overlaps(tx) { // Nonce already pending, check if required price bump is met diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index bd88ef38d8..a4bd7ba83e 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -1108,7 +1108,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) { config := testTxPoolConfig config.AccountSlots = 10 config.GlobalSlots = 0 - + config.AccountSlots = 5 pool := NewTxPool(config, params.TestChainConfig, blockchain) defer pool.Stop() diff --git a/core/types/transaction.go b/core/types/transaction.go index 193447028a..653498a851 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -404,16 +404,21 @@ type TransactionsByPriceAndNonce struct { // if after providing it to the constructor. // It also classifies special txs and normal txs -func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions) (*TransactionsByPriceAndNonce, Transactions) { +func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transactions, signers map[common.Address]struct{}) (*TransactionsByPriceAndNonce, Transactions) { // Initialize a price based heap with the head transactions heads := TxByPrice{} specialTxs := Transactions{} for _, accTxs := range txs { + from, _ := Sender(signer, accTxs[0]) var normalTxs Transactions lastSpecialTx := -1 - for i, tx := range accTxs { - if tx.IsSpecialTransaction() { - lastSpecialTx = i + if len(signers) > 0 { + if _, ok := signers[from]; ok { + for i, tx := range accTxs { + if tx.IsSpecialTransaction() { + lastSpecialTx = i + } + } } } if lastSpecialTx >= 0 { @@ -425,10 +430,9 @@ func NewTransactionsByPriceAndNonce(signer Signer, txs map[common.Address]Transa normalTxs = accTxs } if len(normalTxs) > 0 { - acc, _ := Sender(signer, normalTxs[0]) heads = append(heads, normalTxs[0]) // Ensure the sender address is from the signer - txs[acc] = normalTxs[1:] + txs[from] = normalTxs[1:] } } heap.Init(&heads) diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 602fe8fe23..4e74a0e9b8 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -144,7 +144,7 @@ func TestTransactionPriceNonceSort(t *testing.T) { } } // Sort the transactions and cross check the nonce ordering - txset, _ := NewTransactionsByPriceAndNonce(signer, groups) + txset, _ := NewTransactionsByPriceAndNonce(signer, groups,nil) txs := Transactions{} for tx := txset.Peek(); tx != nil; tx = txset.Peek() { diff --git a/eth/backend.go b/eth/backend.go index 6e6c127cc4..f3790b99db 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -355,6 +355,18 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } return nil } + eth.txPool.IsMasterNode = func(address common.Address) bool { + currentHeader := eth.blockchain.CurrentHeader() + snap, err := c.GetSnapshot(eth.blockchain, currentHeader) + if err != nil { + log.Error("Can't get snap shot with current header ", "number", currentHeader.Number, "hash", currentHeader.Hash().Hex()) + return false + } + if _, ok := snap.Signers[address]; ok { + return true + } + return false + } } return eth, nil diff --git a/miner/worker.go b/miner/worker.go index 3ddb0e25a2..a774cd1a06 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -272,7 +272,7 @@ func (self *worker) update() { self.currentMu.Lock() acc, _ := types.Sender(self.current.signer, ev.Tx) txs := map[common.Address]types.Transactions{acc: {ev.Tx}} - txset, specialTxs := types.NewTransactionsByPriceAndNonce(self.current.signer, txs) + txset, specialTxs := types.NewTransactionsByPriceAndNonce(self.current.signer, txs, nil) self.current.commitTransactions(self.mux, txset, specialTxs, self.chain, self.coinbase) self.currentMu.Unlock() @@ -465,7 +465,7 @@ func (self *worker) commitNewWork() { tstart := time.Now() parent := self.chain.CurrentBlock() - + var signers map[common.Address]struct{} // Only try to commit new work if we are mining if atomic.LoadInt32(&self.mining) == 1 { // check if we are right after parent's coinbase in the list @@ -479,6 +479,7 @@ func (self *worker) commitNewWork() { log.Error("Failed when trying to commit new work", "err", err) return } + signers = snap.Signers preIndex, curIndex, ok, err := posv.YourTurn(masternodes, snap, parent.Header(), self.coinbase) if err != nil { log.Error("Failed when trying to commit new work", "err", err) @@ -576,7 +577,7 @@ func (self *worker) commitNewWork() { log.Error("Failed to fetch pending transactions", "err", err) return } - txs, specialTxs := types.NewTransactionsByPriceAndNonce(self.current.signer, pending) + txs, specialTxs := types.NewTransactionsByPriceAndNonce(self.current.signer, pending, signers) work.commitTransactions(self.mux, txs, specialTxs, self.chain, self.coinbase) // compute uncles for the new block.