From 0930e190a7eec8f956e22ada638e5b97f7ba9cda Mon Sep 17 00:00:00 2001
From: zsfelfoldi <zsfelfoldi@gmail.com>
Date: Tue, 26 May 2015 14:28:32 +0200
Subject: added missing source

---
 eth/gasprice.go | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 174 insertions(+)
 create mode 100644 eth/gasprice.go

(limited to 'eth/gasprice.go')

diff --git a/eth/gasprice.go b/eth/gasprice.go
new file mode 100644
index 000000000..f5b241e2c
--- /dev/null
+++ b/eth/gasprice.go
@@ -0,0 +1,174 @@
+package eth
+
+import (
+	"math/big"
+	"math/rand"
+	"sync"
+
+	"github.com/ethereum/go-ethereum/core"
+	"github.com/ethereum/go-ethereum/core/types"
+	"github.com/ethereum/go-ethereum/event"
+	"github.com/ethereum/go-ethereum/logger"
+	"github.com/ethereum/go-ethereum/logger/glog"
+)
+
+const gpoProcessPastBlocks = 100
+
+type blockPriceInfo struct {
+	baseGasPrice *big.Int
+}
+
+type GasPriceOracle struct {
+	eth                           *Ethereum
+	chain                         *core.ChainManager
+	pool                          *core.TxPool
+	events                        event.Subscription
+	blocks                        map[uint64]*blockPriceInfo
+	firstProcessed, lastProcessed uint64
+	lastBaseMutex                 sync.Mutex
+	lastBase                      *big.Int
+}
+
+func NewGasPriceOracle(eth *Ethereum) (self *GasPriceOracle) {
+	self = &GasPriceOracle{}
+	self.blocks = make(map[uint64]*blockPriceInfo)
+	self.eth = eth
+	self.chain = eth.chainManager
+	self.pool = eth.txPool
+	self.events = eth.EventMux().Subscribe(
+		core.ChainEvent{},
+		core.ChainSplitEvent{},
+		core.TxPreEvent{},
+		core.TxPostEvent{},
+	)
+	self.processPastBlocks()
+	go self.listenLoop()
+	return
+}
+
+func (self *GasPriceOracle) processPastBlocks() {
+	last := self.chain.CurrentBlock().NumberU64()
+	first := uint64(0)
+	if last > gpoProcessPastBlocks {
+		first = last - gpoProcessPastBlocks
+	}
+	self.firstProcessed = first
+	for i := first; i <= last; i++ {
+		self.processBlock(self.chain.GetBlockByNumber(i))
+	}
+
+}
+
+func (self *GasPriceOracle) listenLoop() {
+	for {
+		ev, isopen := <-self.events.Chan()
+		if !isopen {
+			break
+		}
+		switch ev := ev.(type) {
+		case core.ChainEvent:
+			self.processBlock(ev.Block)
+		case core.ChainSplitEvent:
+			self.processBlock(ev.Block)
+		case core.TxPreEvent:
+		case core.TxPostEvent:
+		}
+	}
+	self.events.Unsubscribe()
+}
+
+func (self *GasPriceOracle) processBlock(block *types.Block) {
+	i := block.NumberU64()
+	if i > self.lastProcessed {
+		self.lastProcessed = i
+	}
+
+	lastBase := self.eth.GpoMinGasPrice
+	bpl := self.blocks[i-1]
+	if bpl != nil {
+		lastBase = bpl.baseGasPrice
+	}
+	if lastBase == nil {
+		return
+	}
+
+	var corr int
+	lp := self.lowestPrice(block)
+	if lp == nil {
+		return
+	}
+
+	if lastBase.Cmp(lp) < 0 {
+		corr = self.eth.GpobaseStepUp
+	} else {
+		corr = -self.eth.GpobaseStepDown
+	}
+
+	crand := int64(corr * (900 + rand.Intn(201)))
+	newBase := new(big.Int).Mul(lastBase, big.NewInt(1000000+crand))
+	newBase.Div(newBase, big.NewInt(1000000))
+
+	bpi := self.blocks[i]
+	if bpi == nil {
+		bpi = &blockPriceInfo{}
+		self.blocks[i] = bpi
+	}
+	bpi.baseGasPrice = newBase
+	self.lastBaseMutex.Lock()
+	self.lastBase = newBase
+	self.lastBaseMutex.Unlock()
+
+	glog.V(logger.Detail).Infof("Processed block #%v, base price is %v\n", block.NumberU64(), newBase.Int64())
+}
+
+// returns the lowers possible price with which a tx was or could have been included
+func (self *GasPriceOracle) lowestPrice(block *types.Block) *big.Int {
+	gasUsed := new(big.Int)
+	recepits, err := self.eth.BlockProcessor().GetBlockReceipts(block.Hash())
+	if err != nil {
+		return self.eth.GpoMinGasPrice
+	}
+
+	if len(recepits) > 0 {
+		gasUsed = recepits[len(recepits)-1].CumulativeGasUsed
+	}
+
+	if new(big.Int).Mul(gasUsed, big.NewInt(100)).Cmp(new(big.Int).Mul(block.Header().GasLimit,
+		big.NewInt(int64(self.eth.GpoFullBlockRatio)))) < 0 {
+		// block is not full, could have posted a tx with MinGasPrice
+		return self.eth.GpoMinGasPrice
+	}
+
+	if len(block.Transactions()) < 1 {
+		return self.eth.GpoMinGasPrice
+	}
+
+	// block is full, find smallest gasPrice
+	minPrice := block.Transactions()[0].GasPrice()
+	for i := 1; i < len(block.Transactions()); i++ {
+		price := block.Transactions()[i].GasPrice()
+		if price.Cmp(minPrice) < 0 {
+			minPrice = price
+		}
+	}
+	return minPrice
+}
+
+func (self *GasPriceOracle) SuggestPrice() *big.Int {
+	self.lastBaseMutex.Lock()
+	base := self.lastBase
+	self.lastBaseMutex.Unlock()
+
+	baseCorr := new(big.Int).Mul(base, big.NewInt(int64(100+self.eth.GpobaseCorrectionFactor)))
+	baseCorr.Div(baseCorr, big.NewInt(100))
+
+	if baseCorr.Cmp(self.eth.GpoMinGasPrice) < 0 {
+		return self.eth.GpoMinGasPrice
+	}
+
+	if baseCorr.Cmp(self.eth.GpoMaxGasPrice) > 0 {
+		return self.eth.GpoMaxGasPrice
+	}
+
+	return baseCorr
+}
-- 
cgit v1.2.3


From 2e8016c80d450a7d1126b481f1262b7cd9dec24d Mon Sep 17 00:00:00 2001
From: zsfelfoldi <zsfelfoldi@gmail.com>
Date: Tue, 26 May 2015 14:39:13 +0200
Subject: fixed initial base price bug

---
 eth/gasprice.go | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'eth/gasprice.go')

diff --git a/eth/gasprice.go b/eth/gasprice.go
index f5b241e2c..6f46559a2 100644
--- a/eth/gasprice.go
+++ b/eth/gasprice.go
@@ -159,6 +159,10 @@ func (self *GasPriceOracle) SuggestPrice() *big.Int {
 	base := self.lastBase
 	self.lastBaseMutex.Unlock()
 
+	if base == nil {
+		base = self.eth.GpoMinGasPrice
+	}
+
 	baseCorr := new(big.Int).Mul(base, big.NewInt(int64(100+self.eth.GpobaseCorrectionFactor)))
 	baseCorr.Div(baseCorr, big.NewInt(100))
 
-- 
cgit v1.2.3


From 6e212bdc6d1319c84c305c446bbf1ba9ddfdc66d Mon Sep 17 00:00:00 2001
From: zsfelfoldi <zsfelfoldi@gmail.com>
Date: Tue, 26 May 2015 15:15:54 +0200
Subject: fallback for uninitialized GPO config values

---
 eth/gasprice.go | 3 +++
 1 file changed, 3 insertions(+)

(limited to 'eth/gasprice.go')

diff --git a/eth/gasprice.go b/eth/gasprice.go
index 6f46559a2..12e76fc2c 100644
--- a/eth/gasprice.go
+++ b/eth/gasprice.go
@@ -162,6 +162,9 @@ func (self *GasPriceOracle) SuggestPrice() *big.Int {
 	if base == nil {
 		base = self.eth.GpoMinGasPrice
 	}
+	if base == nil {
+		return big.NewInt(10000000000000) // apparently MinGasPrice is not initialized during some tests
+	}
 
 	baseCorr := new(big.Int).Mul(base, big.NewInt(int64(100+self.eth.GpobaseCorrectionFactor)))
 	baseCorr.Div(baseCorr, big.NewInt(100))
-- 
cgit v1.2.3


From a977cecbe49e9cf049785a437581a767b079570c Mon Sep 17 00:00:00 2001
From: zsfelfoldi <zsfelfoldi@gmail.com>
Date: Wed, 27 May 2015 12:39:59 +0200
Subject: fixed gas price corr. factor

---
 eth/gasprice.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'eth/gasprice.go')

diff --git a/eth/gasprice.go b/eth/gasprice.go
index 12e76fc2c..cd5293691 100644
--- a/eth/gasprice.go
+++ b/eth/gasprice.go
@@ -166,7 +166,7 @@ func (self *GasPriceOracle) SuggestPrice() *big.Int {
 		return big.NewInt(10000000000000) // apparently MinGasPrice is not initialized during some tests
 	}
 
-	baseCorr := new(big.Int).Mul(base, big.NewInt(int64(100+self.eth.GpobaseCorrectionFactor)))
+	baseCorr := new(big.Int).Mul(base, big.NewInt(int64(self.eth.GpobaseCorrectionFactor)))
 	baseCorr.Div(baseCorr, big.NewInt(100))
 
 	if baseCorr.Cmp(self.eth.GpoMinGasPrice) < 0 {
-- 
cgit v1.2.3