@@ -23,49 +23,66 @@ import (
23
23
24
24
"github.com/ethereum/go-ethereum/core"
25
25
"github.com/ethereum/go-ethereum/core/types"
26
- "github.com/ethereum/go-ethereum/event"
27
26
"github.com/ethereum/go-ethereum/logger"
28
27
"github.com/ethereum/go-ethereum/logger/glog"
29
28
)
30
29
31
- const gpoProcessPastBlocks = 100
30
+ const (
31
+ gpoProcessPastBlocks = 100
32
+
33
+ // for testing
34
+ gpoDefaultBaseCorrectionFactor = 110
35
+ gpoDefaultMinGasPrice = 10000000000000
36
+ )
32
37
33
38
type blockPriceInfo struct {
34
39
baseGasPrice * big.Int
35
40
}
36
41
42
+ // GasPriceOracle recommends gas prices based on the content of recent
43
+ // blocks.
37
44
type GasPriceOracle struct {
38
- eth * Ethereum
39
- chain * core.BlockChain
40
- events event.Subscription
45
+ eth * Ethereum
46
+ initOnce sync.Once
47
+ minPrice * big.Int
48
+ lastBaseMutex sync.Mutex
49
+ lastBase * big.Int
50
+
51
+ // state of listenLoop
41
52
blocks map [uint64 ]* blockPriceInfo
42
53
firstProcessed , lastProcessed uint64
43
- lastBaseMutex sync.Mutex
44
- lastBase , minBase * big.Int
54
+ minBase * big.Int
55
+ }
56
+
57
+ // NewGasPriceOracle returns a new oracle.
58
+ func NewGasPriceOracle (eth * Ethereum ) * GasPriceOracle {
59
+ minprice := eth .GpoMinGasPrice
60
+ if minprice == nil {
61
+ minprice = big .NewInt (gpoDefaultMinGasPrice )
62
+ }
63
+ minbase := new (big.Int ).Mul (minprice , big .NewInt (100 ))
64
+ if eth .GpobaseCorrectionFactor > 0 {
65
+ minbase = minbase .Div (minbase , big .NewInt (int64 (eth .GpobaseCorrectionFactor )))
66
+ }
67
+ return & GasPriceOracle {
68
+ eth : eth ,
69
+ blocks : make (map [uint64 ]* blockPriceInfo ),
70
+ minBase : minbase ,
71
+ minPrice : minprice ,
72
+ lastBase : minprice ,
73
+ }
45
74
}
46
75
47
- func NewGasPriceOracle (eth * Ethereum ) (self * GasPriceOracle ) {
48
- self = & GasPriceOracle {}
49
- self .blocks = make (map [uint64 ]* blockPriceInfo )
50
- self .eth = eth
51
- self .chain = eth .blockchain
52
- self .events = eth .EventMux ().Subscribe (
53
- core.ChainEvent {},
54
- core.ChainSplitEvent {},
55
- )
56
-
57
- minbase := new (big.Int ).Mul (self .eth .GpoMinGasPrice , big .NewInt (100 ))
58
- minbase = minbase .Div (minbase , big .NewInt (int64 (self .eth .GpobaseCorrectionFactor )))
59
- self .minBase = minbase
60
-
61
- self .processPastBlocks ()
62
- go self .listenLoop ()
63
- return
76
+ func (gpo * GasPriceOracle ) init () {
77
+ gpo .initOnce .Do (func () {
78
+ gpo .processPastBlocks (gpo .eth .BlockChain ())
79
+ go gpo .listenLoop ()
80
+ })
64
81
}
65
82
66
- func (self * GasPriceOracle ) processPastBlocks () {
83
+ func (self * GasPriceOracle ) processPastBlocks (chain * core. BlockChain ) {
67
84
last := int64 (- 1 )
68
- cblock := self . chain .CurrentBlock ()
85
+ cblock := chain .CurrentBlock ()
69
86
if cblock != nil {
70
87
last = int64 (cblock .NumberU64 ())
71
88
}
@@ -75,7 +92,7 @@ func (self *GasPriceOracle) processPastBlocks() {
75
92
}
76
93
self .firstProcessed = uint64 (first )
77
94
for i := first ; i <= last ; i ++ {
78
- block := self . chain .GetBlockByNumber (uint64 (i ))
95
+ block := chain .GetBlockByNumber (uint64 (i ))
79
96
if block != nil {
80
97
self .processBlock (block )
81
98
}
@@ -84,9 +101,10 @@ func (self *GasPriceOracle) processPastBlocks() {
84
101
}
85
102
86
103
func (self * GasPriceOracle ) listenLoop () {
87
- defer self .events .Unsubscribe ()
104
+ events := self .eth .EventMux ().Subscribe (core.ChainEvent {}, core.ChainSplitEvent {})
105
+ defer events .Unsubscribe ()
88
106
89
- for event := range self . events .Chan () {
107
+ for event := range events .Chan () {
90
108
switch event := event .Data .(type ) {
91
109
case core.ChainEvent :
92
110
self .processBlock (event .Block )
@@ -102,7 +120,7 @@ func (self *GasPriceOracle) processBlock(block *types.Block) {
102
120
self .lastProcessed = i
103
121
}
104
122
105
- lastBase := self .eth . GpoMinGasPrice
123
+ lastBase := self .minPrice
106
124
bpl := self .blocks [i - 1 ]
107
125
if bpl != nil {
108
126
lastBase = bpl .baseGasPrice
@@ -176,28 +194,19 @@ func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int {
176
194
return minPrice
177
195
}
178
196
197
+ // SuggestPrice returns the recommended gas price.
179
198
func (self * GasPriceOracle ) SuggestPrice () * big.Int {
199
+ self .init ()
180
200
self .lastBaseMutex .Lock ()
181
- base := self .lastBase
201
+ price := new (big. Int ). Set ( self .lastBase )
182
202
self .lastBaseMutex .Unlock ()
183
203
184
- if base == nil {
185
- base = self .eth .GpoMinGasPrice
204
+ price .Mul (price , big .NewInt (int64 (self .eth .GpobaseCorrectionFactor )))
205
+ price .Div (price , big .NewInt (100 ))
206
+ if price .Cmp (self .minPrice ) < 0 {
207
+ price .Set (self .minPrice )
208
+ } else if self .eth .GpoMaxGasPrice != nil && price .Cmp (self .eth .GpoMaxGasPrice ) > 0 {
209
+ price .Set (self .eth .GpoMaxGasPrice )
186
210
}
187
- if base == nil {
188
- return big .NewInt (10000000000000 ) // apparently MinGasPrice is not initialized during some tests
189
- }
190
-
191
- baseCorr := new (big.Int ).Mul (base , big .NewInt (int64 (self .eth .GpobaseCorrectionFactor )))
192
- baseCorr .Div (baseCorr , big .NewInt (100 ))
193
-
194
- if baseCorr .Cmp (self .eth .GpoMinGasPrice ) < 0 {
195
- return self .eth .GpoMinGasPrice
196
- }
197
-
198
- if baseCorr .Cmp (self .eth .GpoMaxGasPrice ) > 0 {
199
- return self .eth .GpoMaxGasPrice
200
- }
201
-
202
- return baseCorr
211
+ return price
203
212
}
0 commit comments