Merge pull request #990 from zsfelfoldi/gasprice
eth: add GasPriceOracle
This commit is contained in:
		@@ -256,6 +256,12 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
 | 
			
		||||
		utils.PProfEanbledFlag,
 | 
			
		||||
		utils.PProfPortFlag,
 | 
			
		||||
		utils.SolcPathFlag,
 | 
			
		||||
		utils.GpoMinGasPriceFlag,
 | 
			
		||||
		utils.GpoMaxGasPriceFlag,
 | 
			
		||||
		utils.GpoFullBlockRatioFlag,
 | 
			
		||||
		utils.GpobaseStepDownFlag,
 | 
			
		||||
		utils.GpobaseStepUpFlag,
 | 
			
		||||
		utils.GpobaseCorrectionFactorFlag,
 | 
			
		||||
	}
 | 
			
		||||
	app.Before = func(ctx *cli.Context) error {
 | 
			
		||||
		utils.SetupLogger(ctx)
 | 
			
		||||
 
 | 
			
		||||
@@ -23,10 +23,10 @@ import (
 | 
			
		||||
	"github.com/ethereum/go-ethereum/logger/glog"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/p2p/nat"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/xeth"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/api"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/comms"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/codec"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/rpc/comms"
 | 
			
		||||
	"github.com/ethereum/go-ethereum/xeth"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
@@ -132,7 +132,7 @@ var (
 | 
			
		||||
	GasPriceFlag = cli.StringFlag{
 | 
			
		||||
		Name:  "gasprice",
 | 
			
		||||
		Usage: "Sets the minimal gasprice when mining transactions",
 | 
			
		||||
		Value: new(big.Int).Mul(big.NewInt(10), common.Szabo).String(),
 | 
			
		||||
		Value: new(big.Int).Mul(big.NewInt(1), common.Szabo).String(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	UnlockedAccountFlag = cli.StringFlag{
 | 
			
		||||
@@ -276,6 +276,36 @@ var (
 | 
			
		||||
		Usage: "solidity compiler to be used",
 | 
			
		||||
		Value: "solc",
 | 
			
		||||
	}
 | 
			
		||||
	GpoMinGasPriceFlag = cli.StringFlag{
 | 
			
		||||
		Name:  "gpomin",
 | 
			
		||||
		Usage: "Minimum suggested gas price",
 | 
			
		||||
		Value: new(big.Int).Mul(big.NewInt(1), common.Szabo).String(),
 | 
			
		||||
	}
 | 
			
		||||
	GpoMaxGasPriceFlag = cli.StringFlag{
 | 
			
		||||
		Name:  "gpomax",
 | 
			
		||||
		Usage: "Maximum suggested gas price",
 | 
			
		||||
		Value: new(big.Int).Mul(big.NewInt(100), common.Szabo).String(),
 | 
			
		||||
	}
 | 
			
		||||
	GpoFullBlockRatioFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "gpofull",
 | 
			
		||||
		Usage: "Full block threshold for gas price calculation (%)",
 | 
			
		||||
		Value: 80,
 | 
			
		||||
	}
 | 
			
		||||
	GpobaseStepDownFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "gpobasedown",
 | 
			
		||||
		Usage: "Suggested gas price base step down ratio (1/1000)",
 | 
			
		||||
		Value: 10,
 | 
			
		||||
	}
 | 
			
		||||
	GpobaseStepUpFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "gpobaseup",
 | 
			
		||||
		Usage: "Suggested gas price base step up ratio (1/1000)",
 | 
			
		||||
		Value: 100,
 | 
			
		||||
	}
 | 
			
		||||
	GpobaseCorrectionFactorFlag = cli.IntFlag{
 | 
			
		||||
		Name:  "gpobasecf",
 | 
			
		||||
		Usage: "Suggested gas price base correction factor (%)",
 | 
			
		||||
		Value: 110,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MakeNAT creates a port mapper from set command line flags.
 | 
			
		||||
@@ -313,33 +343,39 @@ func MakeEthConfig(clientID, version string, ctx *cli.Context) *eth.Config {
 | 
			
		||||
		clientID += "/" + customName
 | 
			
		||||
	}
 | 
			
		||||
	return ð.Config{
 | 
			
		||||
		Name:               common.MakeName(clientID, version),
 | 
			
		||||
		DataDir:            ctx.GlobalString(DataDirFlag.Name),
 | 
			
		||||
		ProtocolVersion:    ctx.GlobalInt(ProtocolVersionFlag.Name),
 | 
			
		||||
		GenesisNonce:       ctx.GlobalInt(GenesisNonceFlag.Name),
 | 
			
		||||
		BlockChainVersion:  ctx.GlobalInt(BlockchainVersionFlag.Name),
 | 
			
		||||
		SkipBcVersionCheck: false,
 | 
			
		||||
		NetworkId:          ctx.GlobalInt(NetworkIdFlag.Name),
 | 
			
		||||
		LogFile:            ctx.GlobalString(LogFileFlag.Name),
 | 
			
		||||
		Verbosity:          ctx.GlobalInt(VerbosityFlag.Name),
 | 
			
		||||
		LogJSON:            ctx.GlobalString(LogJSONFlag.Name),
 | 
			
		||||
		Etherbase:          ctx.GlobalString(EtherbaseFlag.Name),
 | 
			
		||||
		MinerThreads:       ctx.GlobalInt(MinerThreadsFlag.Name),
 | 
			
		||||
		AccountManager:     MakeAccountManager(ctx),
 | 
			
		||||
		VmDebug:            ctx.GlobalBool(VMDebugFlag.Name),
 | 
			
		||||
		MaxPeers:           ctx.GlobalInt(MaxPeersFlag.Name),
 | 
			
		||||
		MaxPendingPeers:    ctx.GlobalInt(MaxPendingPeersFlag.Name),
 | 
			
		||||
		Port:               ctx.GlobalString(ListenPortFlag.Name),
 | 
			
		||||
		NAT:                MakeNAT(ctx),
 | 
			
		||||
		NatSpec:            ctx.GlobalBool(NatspecEnabledFlag.Name),
 | 
			
		||||
		Discovery:          !ctx.GlobalBool(NoDiscoverFlag.Name),
 | 
			
		||||
		NodeKey:            MakeNodeKey(ctx),
 | 
			
		||||
		Shh:                ctx.GlobalBool(WhisperEnabledFlag.Name),
 | 
			
		||||
		Dial:               true,
 | 
			
		||||
		BootNodes:          ctx.GlobalString(BootnodesFlag.Name),
 | 
			
		||||
		GasPrice:           common.String2Big(ctx.GlobalString(GasPriceFlag.Name)),
 | 
			
		||||
		SolcPath:           ctx.GlobalString(SolcPathFlag.Name),
 | 
			
		||||
		AutoDAG:            ctx.GlobalBool(AutoDAGFlag.Name) || ctx.GlobalBool(MiningEnabledFlag.Name),
 | 
			
		||||
		Name:                    common.MakeName(clientID, version),
 | 
			
		||||
		DataDir:                 ctx.GlobalString(DataDirFlag.Name),
 | 
			
		||||
		ProtocolVersion:         ctx.GlobalInt(ProtocolVersionFlag.Name),
 | 
			
		||||
		GenesisNonce:            ctx.GlobalInt(GenesisNonceFlag.Name),
 | 
			
		||||
		BlockChainVersion:       ctx.GlobalInt(BlockchainVersionFlag.Name),
 | 
			
		||||
		SkipBcVersionCheck:      false,
 | 
			
		||||
		NetworkId:               ctx.GlobalInt(NetworkIdFlag.Name),
 | 
			
		||||
		LogFile:                 ctx.GlobalString(LogFileFlag.Name),
 | 
			
		||||
		Verbosity:               ctx.GlobalInt(VerbosityFlag.Name),
 | 
			
		||||
		LogJSON:                 ctx.GlobalString(LogJSONFlag.Name),
 | 
			
		||||
		Etherbase:               ctx.GlobalString(EtherbaseFlag.Name),
 | 
			
		||||
		MinerThreads:            ctx.GlobalInt(MinerThreadsFlag.Name),
 | 
			
		||||
		AccountManager:          MakeAccountManager(ctx),
 | 
			
		||||
		VmDebug:                 ctx.GlobalBool(VMDebugFlag.Name),
 | 
			
		||||
		MaxPeers:                ctx.GlobalInt(MaxPeersFlag.Name),
 | 
			
		||||
		MaxPendingPeers:         ctx.GlobalInt(MaxPendingPeersFlag.Name),
 | 
			
		||||
		Port:                    ctx.GlobalString(ListenPortFlag.Name),
 | 
			
		||||
		NAT:                     MakeNAT(ctx),
 | 
			
		||||
		NatSpec:                 ctx.GlobalBool(NatspecEnabledFlag.Name),
 | 
			
		||||
		Discovery:               !ctx.GlobalBool(NoDiscoverFlag.Name),
 | 
			
		||||
		NodeKey:                 MakeNodeKey(ctx),
 | 
			
		||||
		Shh:                     ctx.GlobalBool(WhisperEnabledFlag.Name),
 | 
			
		||||
		Dial:                    true,
 | 
			
		||||
		BootNodes:               ctx.GlobalString(BootnodesFlag.Name),
 | 
			
		||||
		GasPrice:                common.String2Big(ctx.GlobalString(GasPriceFlag.Name)),
 | 
			
		||||
		GpoMinGasPrice:          common.String2Big(ctx.GlobalString(GpoMinGasPriceFlag.Name)),
 | 
			
		||||
		GpoMaxGasPrice:          common.String2Big(ctx.GlobalString(GpoMaxGasPriceFlag.Name)),
 | 
			
		||||
		GpoFullBlockRatio:       ctx.GlobalInt(GpoFullBlockRatioFlag.Name),
 | 
			
		||||
		GpobaseStepDown:         ctx.GlobalInt(GpobaseStepDownFlag.Name),
 | 
			
		||||
		GpobaseStepUp:           ctx.GlobalInt(GpobaseStepUpFlag.Name),
 | 
			
		||||
		GpobaseCorrectionFactor: ctx.GlobalInt(GpobaseCorrectionFactorFlag.Name),
 | 
			
		||||
		SolcPath:                ctx.GlobalString(SolcPathFlag.Name),
 | 
			
		||||
		AutoDAG:                 ctx.GlobalBool(AutoDAGFlag.Name) || ctx.GlobalBool(MiningEnabledFlag.Name),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -396,7 +432,7 @@ func IpcSocketPath(ctx *cli.Context) (ipcpath string) {
 | 
			
		||||
		if ctx.GlobalString(IPCPathFlag.Name) != common.DefaultIpcPath() {
 | 
			
		||||
			ipcpath = ctx.GlobalString(IPCPathFlag.Name)
 | 
			
		||||
		} else if ctx.GlobalString(DataDirFlag.Name) != "" &&
 | 
			
		||||
		ctx.GlobalString(DataDirFlag.Name) != common.DefaultDataDir() {
 | 
			
		||||
			ctx.GlobalString(DataDirFlag.Name) != common.DefaultDataDir() {
 | 
			
		||||
			ipcpath = filepath.Join(ctx.GlobalString(DataDirFlag.Name), "geth.ipc")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -260,6 +260,12 @@ func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs st
 | 
			
		||||
		putTx(sm.extraDb, tx, block, uint64(i))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	receiptsRlp := receipts.RlpEncode()
 | 
			
		||||
	/*if len(receipts) > 0 {
 | 
			
		||||
		glog.V(logger.Info).Infof("Saving %v receipts, rlp len is %v\n", len(receipts), len(receiptsRlp))
 | 
			
		||||
	}*/
 | 
			
		||||
	sm.extraDb.Put(append(receiptsPre, block.Hash().Bytes()...), receiptsRlp)
 | 
			
		||||
 | 
			
		||||
	return state.Logs(), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -404,6 +410,8 @@ func getBlockReceipts(db common.Database, bhash common.Hash) (receipts types.Rec
 | 
			
		||||
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		err = rlp.DecodeBytes(rdata, &receipts)
 | 
			
		||||
	} else {
 | 
			
		||||
		glog.V(logger.Detail).Infof("getBlockReceipts error %v\n", err)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -93,6 +93,13 @@ type Config struct {
 | 
			
		||||
	AccountManager *accounts.Manager
 | 
			
		||||
	SolcPath       string
 | 
			
		||||
 | 
			
		||||
	GpoMinGasPrice          *big.Int
 | 
			
		||||
	GpoMaxGasPrice          *big.Int
 | 
			
		||||
	GpoFullBlockRatio       int
 | 
			
		||||
	GpobaseStepDown         int
 | 
			
		||||
	GpobaseStepUp           int
 | 
			
		||||
	GpobaseCorrectionFactor int
 | 
			
		||||
 | 
			
		||||
	// NewDB is used to create databases.
 | 
			
		||||
	// If nil, the default is to create leveldb databases on disk.
 | 
			
		||||
	NewDB func(path string) (common.Database, error)
 | 
			
		||||
@@ -196,6 +203,13 @@ type Ethereum struct {
 | 
			
		||||
	SolcPath        string
 | 
			
		||||
	solc            *compiler.Solidity
 | 
			
		||||
 | 
			
		||||
	GpoMinGasPrice          *big.Int
 | 
			
		||||
	GpoMaxGasPrice          *big.Int
 | 
			
		||||
	GpoFullBlockRatio       int
 | 
			
		||||
	GpobaseStepDown         int
 | 
			
		||||
	GpobaseStepUp           int
 | 
			
		||||
	GpobaseCorrectionFactor int
 | 
			
		||||
 | 
			
		||||
	net      *p2p.Server
 | 
			
		||||
	eventMux *event.TypeMux
 | 
			
		||||
	miner    *miner.Miner
 | 
			
		||||
@@ -265,22 +279,28 @@ func New(config *Config) (*Ethereum, error) {
 | 
			
		||||
	glog.V(logger.Info).Infof("Blockchain DB Version: %d", config.BlockChainVersion)
 | 
			
		||||
 | 
			
		||||
	eth := &Ethereum{
 | 
			
		||||
		shutdownChan:    make(chan bool),
 | 
			
		||||
		databasesClosed: make(chan bool),
 | 
			
		||||
		blockDb:         blockDb,
 | 
			
		||||
		stateDb:         stateDb,
 | 
			
		||||
		extraDb:         extraDb,
 | 
			
		||||
		eventMux:        &event.TypeMux{},
 | 
			
		||||
		accountManager:  config.AccountManager,
 | 
			
		||||
		DataDir:         config.DataDir,
 | 
			
		||||
		etherbase:       common.HexToAddress(config.Etherbase),
 | 
			
		||||
		clientVersion:   config.Name, // TODO should separate from Name
 | 
			
		||||
		ethVersionId:    config.ProtocolVersion,
 | 
			
		||||
		netVersionId:    config.NetworkId,
 | 
			
		||||
		NatSpec:         config.NatSpec,
 | 
			
		||||
		MinerThreads:    config.MinerThreads,
 | 
			
		||||
		SolcPath:        config.SolcPath,
 | 
			
		||||
		AutoDAG:         config.AutoDAG,
 | 
			
		||||
		shutdownChan:            make(chan bool),
 | 
			
		||||
		databasesClosed:         make(chan bool),
 | 
			
		||||
		blockDb:                 blockDb,
 | 
			
		||||
		stateDb:                 stateDb,
 | 
			
		||||
		extraDb:                 extraDb,
 | 
			
		||||
		eventMux:                &event.TypeMux{},
 | 
			
		||||
		accountManager:          config.AccountManager,
 | 
			
		||||
		DataDir:                 config.DataDir,
 | 
			
		||||
		etherbase:               common.HexToAddress(config.Etherbase),
 | 
			
		||||
		clientVersion:           config.Name, // TODO should separate from Name
 | 
			
		||||
		ethVersionId:            config.ProtocolVersion,
 | 
			
		||||
		netVersionId:            config.NetworkId,
 | 
			
		||||
		NatSpec:                 config.NatSpec,
 | 
			
		||||
		MinerThreads:            config.MinerThreads,
 | 
			
		||||
		SolcPath:                config.SolcPath,
 | 
			
		||||
		AutoDAG:                 config.AutoDAG,
 | 
			
		||||
		GpoMinGasPrice:          config.GpoMinGasPrice,
 | 
			
		||||
		GpoMaxGasPrice:          config.GpoMaxGasPrice,
 | 
			
		||||
		GpoFullBlockRatio:       config.GpoFullBlockRatio,
 | 
			
		||||
		GpobaseStepDown:         config.GpobaseStepDown,
 | 
			
		||||
		GpobaseStepUp:           config.GpobaseStepUp,
 | 
			
		||||
		GpobaseCorrectionFactor: config.GpobaseCorrectionFactor,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	eth.pow = ethash.New()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										181
									
								
								eth/gasprice.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								eth/gasprice.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,181 @@
 | 
			
		||||
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()
 | 
			
		||||
 | 
			
		||||
	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(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
 | 
			
		||||
}
 | 
			
		||||
@@ -59,7 +59,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err
 | 
			
		||||
	case "eth_mining":
 | 
			
		||||
		*reply = api.xeth().IsMining()
 | 
			
		||||
	case "eth_gasPrice":
 | 
			
		||||
		v := xeth.DefaultGasPrice()
 | 
			
		||||
		v := api.xeth().DefaultGasPrice()
 | 
			
		||||
		*reply = newHexNum(v.Bytes())
 | 
			
		||||
	case "eth_accounts":
 | 
			
		||||
		*reply = api.xeth().Accounts()
 | 
			
		||||
 
 | 
			
		||||
@@ -139,7 +139,7 @@ func (self *ethApi) IsMining(req *shared.Request) (interface{}, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *ethApi) GasPrice(req *shared.Request) (interface{}, error) {
 | 
			
		||||
	return newHexNum(xeth.DefaultGasPrice().Bytes()), nil
 | 
			
		||||
	return newHexNum(self.xeth.DefaultGasPrice().Bytes()), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (self *ethApi) GetStorage(req *shared.Request) (interface{}, error) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								xeth/xeth.go
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								xeth/xeth.go
									
									
									
									
									
								
							@@ -39,8 +39,14 @@ const (
 | 
			
		||||
	LogFilterTy
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func DefaultGas() *big.Int      { return new(big.Int).Set(defaultGas) }
 | 
			
		||||
func DefaultGasPrice() *big.Int { return new(big.Int).Set(defaultGasPrice) }
 | 
			
		||||
func DefaultGas() *big.Int { return new(big.Int).Set(defaultGas) }
 | 
			
		||||
 | 
			
		||||
func (self *XEth) DefaultGasPrice() *big.Int {
 | 
			
		||||
	if self.gpo == nil {
 | 
			
		||||
		self.gpo = eth.NewGasPriceOracle(self.backend)
 | 
			
		||||
	}
 | 
			
		||||
	return self.gpo.SuggestPrice()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type XEth struct {
 | 
			
		||||
	backend  *eth.Ethereum
 | 
			
		||||
@@ -68,6 +74,8 @@ type XEth struct {
 | 
			
		||||
	// register map[string][]*interface{} // TODO improve return type
 | 
			
		||||
 | 
			
		||||
	agent *miner.RemoteAgent
 | 
			
		||||
 | 
			
		||||
	gpo *eth.GasPriceOracle
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTest(eth *eth.Ethereum, frontend Frontend) *XEth {
 | 
			
		||||
@@ -80,22 +88,22 @@ func NewTest(eth *eth.Ethereum, frontend Frontend) *XEth {
 | 
			
		||||
// New creates an XEth that uses the given frontend.
 | 
			
		||||
// If a nil Frontend is provided, a default frontend which
 | 
			
		||||
// confirms all transactions will be used.
 | 
			
		||||
func New(eth *eth.Ethereum, frontend Frontend) *XEth {
 | 
			
		||||
func New(ethereum *eth.Ethereum, frontend Frontend) *XEth {
 | 
			
		||||
	xeth := &XEth{
 | 
			
		||||
		backend:          eth,
 | 
			
		||||
		backend:          ethereum,
 | 
			
		||||
		frontend:         frontend,
 | 
			
		||||
		quit:             make(chan struct{}),
 | 
			
		||||
		filterManager:    filter.NewFilterManager(eth.EventMux()),
 | 
			
		||||
		filterManager:    filter.NewFilterManager(ethereum.EventMux()),
 | 
			
		||||
		logQueue:         make(map[int]*logQueue),
 | 
			
		||||
		blockQueue:       make(map[int]*hashQueue),
 | 
			
		||||
		transactionQueue: make(map[int]*hashQueue),
 | 
			
		||||
		messages:         make(map[int]*whisperFilter),
 | 
			
		||||
		agent:            miner.NewRemoteAgent(),
 | 
			
		||||
	}
 | 
			
		||||
	if eth.Whisper() != nil {
 | 
			
		||||
		xeth.whisper = NewWhisper(eth.Whisper())
 | 
			
		||||
	if ethereum.Whisper() != nil {
 | 
			
		||||
		xeth.whisper = NewWhisper(ethereum.Whisper())
 | 
			
		||||
	}
 | 
			
		||||
	eth.Miner().Register(xeth.agent)
 | 
			
		||||
	ethereum.Miner().Register(xeth.agent)
 | 
			
		||||
	if frontend == nil {
 | 
			
		||||
		xeth.frontend = dummyFrontend{}
 | 
			
		||||
	}
 | 
			
		||||
@@ -227,6 +235,7 @@ func (self *XEth) WithState(statedb *state.StateDB) *XEth {
 | 
			
		||||
	xeth := &XEth{
 | 
			
		||||
		backend:  self.backend,
 | 
			
		||||
		frontend: self.frontend,
 | 
			
		||||
		gpo:      self.gpo,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	xeth.state = NewState(xeth, statedb)
 | 
			
		||||
@@ -829,7 +838,7 @@ func (self *XEth) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr, dataStr st
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if msg.gasPrice.Cmp(big.NewInt(0)) == 0 {
 | 
			
		||||
		msg.gasPrice = DefaultGasPrice()
 | 
			
		||||
		msg.gasPrice = self.DefaultGasPrice()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	block := self.CurrentBlock()
 | 
			
		||||
@@ -898,7 +907,7 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(gasPriceStr) == 0 {
 | 
			
		||||
		price = DefaultGasPrice()
 | 
			
		||||
		price = self.DefaultGasPrice()
 | 
			
		||||
	} else {
 | 
			
		||||
		price = common.Big(gasPriceStr)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user