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

---
 eth/gasprice.go | 174 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 174 insertions(+)
 create mode 100644 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
+}
-- 
GitLab