aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/transaction_pool.go67
-rw-r--r--core/transaction_pool_test.go11
-rw-r--r--eth/api.go2
-rw-r--r--xeth/xeth.go1
4 files changed, 76 insertions, 5 deletions
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
index 16f66efdc..7dcc2aac2 100644
--- a/core/transaction_pool.go
+++ b/core/transaction_pool.go
@@ -22,6 +22,7 @@ import (
"math/big"
"sort"
"sync"
+ "time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
@@ -65,10 +66,10 @@ type TxPool struct {
minGasPrice *big.Int
eventMux *event.TypeMux
events event.Subscription
-
- mu sync.RWMutex
- pending map[common.Hash]*types.Transaction // processable transactions
- queue map[common.Address]map[common.Hash]*types.Transaction
+ localTx *txSet
+ mu sync.RWMutex
+ pending map[common.Hash]*types.Transaction // processable transactions
+ queue map[common.Address]map[common.Hash]*types.Transaction
}
func NewTxPool(eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool {
@@ -81,6 +82,7 @@ func NewTxPool(eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func(
gasLimit: gasLimitFn,
minGasPrice: new(big.Int),
pendingState: nil,
+ localTx: newTxSet(),
events: eventMux.Subscribe(ChainHeadEvent{}, GasPriceChanged{}, RemovedTransactionEvent{}),
}
go pool.eventLoop()
@@ -168,6 +170,14 @@ func (pool *TxPool) Stats() (pending int, queued int) {
return
}
+// SetLocal marks a transaction as local, skipping gas price
+// check against local miner minimum in the future
+func (pool *TxPool) SetLocal(tx *types.Transaction) {
+ pool.mu.Lock()
+ defer pool.mu.Unlock()
+ pool.localTx.add(tx.Hash())
+}
+
// validateTx checks whether a transaction is valid according
// to the consensus rules.
func (pool *TxPool) validateTx(tx *types.Transaction) error {
@@ -177,8 +187,9 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
err error
)
+ local := pool.localTx.contains(tx.Hash())
// Drop transactions under our own minimal accepted gas price
- if pool.minGasPrice.Cmp(tx.GasPrice()) > 0 {
+ if !local && pool.minGasPrice.Cmp(tx.GasPrice()) > 0 {
return ErrCheap
}
@@ -489,3 +500,49 @@ type txQueueEntry struct {
func (q txQueue) Len() int { return len(q) }
func (q txQueue) Swap(i, j int) { q[i], q[j] = q[j], q[i] }
func (q txQueue) Less(i, j int) bool { return q[i].Nonce() < q[j].Nonce() }
+
+// txSet represents a set of transaction hashes in which entries
+// are automatically dropped after txSetDuration time
+type txSet struct {
+ txMap map[common.Hash]struct{}
+ txOrd map[uint64]txOrdType
+ addPtr, delPtr uint64
+}
+
+const txSetDuration = time.Hour * 2
+
+// txOrdType represents an entry in the time-ordered list of transaction hashes
+type txOrdType struct {
+ hash common.Hash
+ time time.Time
+}
+
+// newTxSet creates a new transaction set
+func newTxSet() *txSet {
+ return &txSet{
+ txMap: make(map[common.Hash]struct{}),
+ txOrd: make(map[uint64]txOrdType),
+ }
+}
+
+// contains returns true if the set contains the given transaction hash
+// (not thread safe, should be called from a locked environment)
+func (self *txSet) contains(hash common.Hash) bool {
+ _, ok := self.txMap[hash]
+ return ok
+}
+
+// add adds a transaction hash to the set, then removes entries older than txSetDuration
+// (not thread safe, should be called from a locked environment)
+func (self *txSet) add(hash common.Hash) {
+ self.txMap[hash] = struct{}{}
+ now := time.Now()
+ self.txOrd[self.addPtr] = txOrdType{hash: hash, time: now}
+ self.addPtr++
+ delBefore := now.Add(-txSetDuration)
+ for self.delPtr < self.addPtr && self.txOrd[self.delPtr].time.Before(delBefore) {
+ delete(self.txMap, self.txOrd[self.delPtr].hash)
+ delete(self.txOrd, self.delPtr)
+ self.delPtr++
+ }
+}
diff --git a/core/transaction_pool_test.go b/core/transaction_pool_test.go
index 229dcacf3..a311bdd66 100644
--- a/core/transaction_pool_test.go
+++ b/core/transaction_pool_test.go
@@ -72,6 +72,17 @@ func TestInvalidTransactions(t *testing.T) {
if err := pool.Add(tx); err != ErrNonce {
t.Error("expected", ErrNonce)
}
+
+ tx = transaction(1, big.NewInt(100000), key)
+ pool.minGasPrice = big.NewInt(1000)
+ if err := pool.Add(tx); err != ErrCheap {
+ t.Error("expected", ErrCheap, "got", err)
+ }
+
+ pool.SetLocal(tx)
+ if err := pool.Add(tx); err != nil {
+ t.Error("expected", nil, "got", err)
+ }
}
func TestTransactionQueue(t *testing.T) {
diff --git a/eth/api.go b/eth/api.go
index 068b350db..a1630e2d1 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -926,6 +926,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(args SendTxArgs) (common.Hash
return common.Hash{}, err
}
+ s.txPool.SetLocal(signedTx)
if err := s.txPool.Add(signedTx); err != nil {
return common.Hash{}, nil
}
@@ -948,6 +949,7 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(encodedTx string) (string,
return "", err
}
+ s.txPool.SetLocal(tx)
if err := s.txPool.Add(tx); err != nil {
return "", err
}
diff --git a/xeth/xeth.go b/xeth/xeth.go
index 85bf41a82..5a5399a3e 100644
--- a/xeth/xeth.go
+++ b/xeth/xeth.go
@@ -1044,6 +1044,7 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS
if err != nil {
return "", err
}
+ self.EthereumService().TxPool().SetLocal(signed)
if err = self.EthereumService().TxPool().Add(signed); err != nil {
return "", err
}