diff --git a/consensus/consensus.go b/consensus/consensus.go
index 9c663c4c34..adef596a27 100644
--- a/consensus/consensus.go
+++ b/consensus/consensus.go
@@ -84,7 +84,7 @@ type Engine interface {
// Note: The block header and state database might be updated to reflect any
// consensus rules that happen at finalization (e.g. block rewards).
Finalize(chain ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
- uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error)
+ uncles []*types.Header, receipts []*types.Receipt, LcpContext *types.LCPContext) (*types.Block, error)
// Seal generates a new block for the given input block with the local miner's
// seal place on top.
diff --git a/consensus/lcp/lcp.go b/consensus/lcp/lcp.go
index e69e532b0f..b961663a01 100644
--- a/consensus/lcp/lcp.go
+++ b/consensus/lcp/lcp.go
@@ -356,7 +356,7 @@ func AccumulateRewards(config *params.ChainConfig, state *state.StateDB, header
}
func (d *LCP) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
- uncles []*types.Header, receipts []*types.Receipt, lcpContext *types.LCPContext) (*types.Block, error) {
+ uncles []*types.Header, receipts []*types.Receipt, LcpContext *types.LCPContext) (*types.Block, error) {
// Accumulate block rewards and commit the final state root
AccumulateRewards(chain.Config(), state, header, uncles)
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
@@ -364,7 +364,7 @@ func (d *LCP) Finalize(chain consensus.ChainReader, header *types.Header, state
parent := chain.GetHeaderByHash(header.ParentHash)
epochContext := &EpochContext{
statedb: state,
- Context: lcpContext,
+ Context: LcpContext,
TimeStamp: header.Time.Int64(),
}
if timeOfFirstBlock == 0 {
@@ -379,8 +379,8 @@ func (d *LCP) Finalize(chain consensus.ChainReader, header *types.Header, state
}
//update mint count trie
- updateMintCnt(parent.Time.Int64(), header.Time.Int64(), header.Validator, lcpContext)
- header.LCPContext = lcpContext.ToProto()
+ updateMintCnt(parent.Time.Int64(), header.Time.Int64(), header.Validator, LcpContext)
+ header.LCPContext = LcpContext.ToProto()
return types.NewBlock(header, txs, uncles, receipts), nil
}
@@ -497,8 +497,8 @@ func NextSlot(now int64) int64 {
}
// update counts in MintCntTrie for the miner of newBlock
-func updateMintCnt(parentBlockTime, currentBlockTime int64, validator common.Address, lcpContext *types.LCPContext) {
- currentMintCntTrie := lcpContext.MintCntTrie()
+func updateMintCnt(parentBlockTime, currentBlockTime int64, validator common.Address, dposContext *types.LCPContext) {
+ currentMintCntTrie := dposContext.MintCntTrie()
currentEpoch := parentBlockTime / epochInterval
currentEpochBytes := make([]byte, 8)
binary.BigEndian.PutUint64(currentEpochBytes, uint64(currentEpoch))
@@ -524,5 +524,5 @@ func updateMintCnt(parentBlockTime, currentBlockTime int64, validator common.Add
newEpochBytes := make([]byte, 8)
binary.BigEndian.PutUint64(newEpochBytes, uint64(newEpoch))
binary.BigEndian.PutUint64(newCntBytes, uint64(cnt))
- lcpContext.MintCntTrie().TryUpdate(append(newEpochBytes, validator.Bytes()...), newCntBytes)
+ dposContext.MintCntTrie().TryUpdate(append(newEpochBytes, validator.Bytes()...), newCntBytes)
}
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 07553240a8..c2823cd06c 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -28,6 +28,7 @@ import (
"github.com/pavelkrolevets/go-ethereum/core/vm"
"github.com/pavelkrolevets/go-ethereum/ethdb"
"github.com/pavelkrolevets/go-ethereum/params"
+ "github.com/pavelkrolevets/go-ethereum/consensus/lcp"
)
// BlockGen creates blocks for testing.
@@ -167,7 +168,7 @@ func (b *BlockGen) OffsetTime(seconds int64) {
func GenerateChain(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
// Force LCP configuration if everything is empty
if config == nil {
- config = params.TestChainConfig
+ config = params.LcpChainConfig
}
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
@@ -195,9 +196,9 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
if gen != nil {
gen(i, b)
}
-
+ lcp.AccumulateRewards(config, statedb, b.header, b.uncles)
if b.engine != nil {
- block, _ := b.engine.Finalize(b.chainReader, b.header, statedb, b.txs, b.uncles, b.receipts)
+ block, _ := b.engine.Finalize(b.chainReader, b.header, statedb, b.txs, b.uncles, b.receipts, b.header.LCPContext)
// Write state changes to db
root, err := statedb.Commit(config.IsEIP158(b.header.Number))
if err != nil {
@@ -206,10 +207,13 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
if err := statedb.Database().TrieDB().Commit(root, false); err != nil {
panic(fmt.Sprintf("trie write error: %v", err))
}
+ b.header.Root = root
+ b.header.LCPContext = parent.Header().LCPContext
return block, b.receipts
}
return nil, nil
}
+
for i := 0; i < n; i++ {
statedb, err := state.New(parent.Root(), state.NewDatabase(db))
if err != nil {
diff --git a/core/database_util_test.go b/core/database_util_test.go
index 29234d5e2c..6f7129121a 100644
--- a/core/database_util_test.go
+++ b/core/database_util_test.go
@@ -66,11 +66,11 @@ func TestHeaderStorage(t *testing.T) {
// Tests block body storage and retrieval operations.
func TestBodyStorage(t *testing.T) {
- db, _ := ethdb.NewMemDatabase()
+ db:= ethdb.NewMemDatabase()
// Create a test body to move around the database and make sure it's really new
- dposCtx, _ := types.NewDposContext(db)
- body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header"), DposContext: dposCtx.ToProto()}}}
+ dposCtx, _ := types.NewLCPContext(db)
+ body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header"), LCPContext: dposCtx.ToProto()}}}
hasher := sha3.NewKeccak256()
rlp.Encode(hasher, body)
@@ -107,7 +107,7 @@ func TestBodyStorage(t *testing.T) {
// Tests block storage and retrieval operations.
func TestBlockStorage(t *testing.T) {
- db, _ := ethdb.NewMemDatabase()
+ db:= ethdb.NewMemDatabase()
// Create a test block to move around the database and make sure it's really new
block := types.NewBlockWithHeader(&types.Header{
@@ -159,7 +159,7 @@ func TestBlockStorage(t *testing.T) {
// Tests that partial block contents don't get reassembled into full blocks.
func TestPartialBlockStorage(t *testing.T) {
- db, _ := ethdb.NewMemDatabase()
+ db:= ethdb.NewMemDatabase()
block := types.NewBlockWithHeader(&types.Header{
Extra: []byte("test block"),
UncleHash: types.EmptyUncleHash,
@@ -200,7 +200,7 @@ func TestPartialBlockStorage(t *testing.T) {
// Tests block total difficulty storage and retrieval operations.
func TestTdStorage(t *testing.T) {
- db, _ := ethdb.NewMemDatabase()
+ db:= ethdb.NewMemDatabase()
// Create a test TD to move around the database and make sure it's really new
hash, td := common.Hash{}, big.NewInt(314)
@@ -225,7 +225,7 @@ func TestTdStorage(t *testing.T) {
// Tests that canonical numbers can be mapped to hashes and retrieved.
func TestCanonicalMappingStorage(t *testing.T) {
- db, _ := ethdb.NewMemDatabase()
+ db:= ethdb.NewMemDatabase()
// Create a test canonical number and assinged hash to move around
hash, number := common.Hash{0: 0xff}, uint64(314)
@@ -250,7 +250,7 @@ func TestCanonicalMappingStorage(t *testing.T) {
// Tests that head headers and head blocks can be assigned, individually.
func TestHeadStorage(t *testing.T) {
- db, _ := ethdb.NewMemDatabase()
+ db:= ethdb.NewMemDatabase()
blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header")})
blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full")})
@@ -290,11 +290,11 @@ func TestHeadStorage(t *testing.T) {
// Tests that positional lookup metadata can be stored and retrieved.
func TestLookupStorage(t *testing.T) {
- db, _ := ethdb.NewMemDatabase()
+ db:= ethdb.NewMemDatabase()
- tx1 := types.NewTransaction(types.Binary, 1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), big.NewInt(1111), big.NewInt(11111), []byte{0x11, 0x11, 0x11})
- tx2 := types.NewTransaction(types.Binary, 2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), big.NewInt(2222), big.NewInt(22222), []byte{0x22, 0x22, 0x22})
- tx3 := types.NewTransaction(types.Binary, 3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), big.NewInt(3333), big.NewInt(33333), []byte{0x33, 0x33, 0x33})
+ tx1 := types.NewTransaction(types.Binary, 1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
+ tx2 := types.NewTransaction(types.Binary, 2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22})
+ tx3 := types.NewTransaction(types.Binary, 3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33})
txs := []*types.Transaction{tx1, tx2, tx3}
block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil)
@@ -335,29 +335,29 @@ func TestLookupStorage(t *testing.T) {
// Tests that receipts associated with a single block can be stored and retrieved.
func TestBlockReceiptStorage(t *testing.T) {
- db, _ := ethdb.NewMemDatabase()
+ db:= ethdb.NewMemDatabase()
receipt1 := &types.Receipt{
Status: types.ReceiptStatusFailed,
- CumulativeGasUsed: big.NewInt(1),
+ CumulativeGasUsed: 1,
Logs: []*types.Log{
{Address: common.BytesToAddress([]byte{0x11})},
{Address: common.BytesToAddress([]byte{0x01, 0x11})},
},
TxHash: common.BytesToHash([]byte{0x11, 0x11}),
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
- GasUsed: big.NewInt(111111),
+ GasUsed: 111111,
}
receipt2 := &types.Receipt{
PostState: common.Hash{2}.Bytes(),
- CumulativeGasUsed: big.NewInt(2),
+ CumulativeGasUsed: 2,
Logs: []*types.Log{
{Address: common.BytesToAddress([]byte{0x22})},
{Address: common.BytesToAddress([]byte{0x02, 0x22})},
},
TxHash: common.BytesToHash([]byte{0x22, 0x22}),
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
- GasUsed: big.NewInt(222222),
+ GasUsed: 222222,
}
receipts := []*types.Receipt{receipt1, receipt2}
diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go
index 88b9e9b378..1845340e88 100644
--- a/core/tx_pool_test.go
+++ b/core/tx_pool_test.go
@@ -73,7 +73,7 @@ func transaction(nonce uint64, gaslimit uint64, key *ecdsa.PrivateKey) *types.Tr
}
func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
- tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, gasprice, nil), types.HomesteadSigner{}, key)
+ tx, _ := types.SignTx(types.NewTransaction(types.Binary, nonce, common.Address{}, big.NewInt(100), gaslimit, gasprice, nil), types.HomesteadSigner{}, key)
return tx
}
@@ -319,7 +319,7 @@ func TestTransactionNegativeValue(t *testing.T) {
pool, key := setupTxPool()
defer pool.Stop()
- tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key)
+ tx, _ := types.SignTx(types.NewTransaction(types.Binary,0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key)
from, _ := deriveSender(tx)
pool.currentState.AddBalance(from, big.NewInt(1))
if err := pool.AddRemote(tx); err != ErrNegativeValue {
@@ -373,9 +373,9 @@ func TestTransactionDoubleNonce(t *testing.T) {
resetState()
signer := types.HomesteadSigner{}
- tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 100000, big.NewInt(1), nil), signer, key)
- tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(2), nil), signer, key)
- tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(1), nil), signer, key)
+ tx1, _ := types.SignTx(types.NewTransaction(types.Binary, 0, common.Address{}, big.NewInt(100), 100000, big.NewInt(1), nil), signer, key)
+ tx2, _ := types.SignTx(types.NewTransaction(types.Binary,0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(2), nil), signer, key)
+ tx3, _ := types.SignTx(types.NewTransaction(types.Binary,0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(1), nil), signer, key)
// Add the first two transaction, ensure higher priced stays only
if replace, err := pool.add(tx1, false); err != nil || replace {
diff --git a/core/types/block.go b/core/types/block.go
index 32ad088eae..dd82f6ec66 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -73,7 +73,7 @@ type Header struct {
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
Validator common.Address `json:"validator" gencodec:"required"`
LCPContext *LCPContextProto `json:"LCPContext" gencodec:"required"`
- Coinbase common.Address `json:"miner" gencodec:"required"`
+ Coinbase common.Address `json:"coinbase" gencodec:"required"`
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
diff --git a/eth/backend.go b/eth/backend.go
index c0408ae605..ae8a2857b2 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -29,8 +29,6 @@ import (
"github.com/pavelkrolevets/go-ethereum/common"
"github.com/pavelkrolevets/go-ethereum/common/hexutil"
"github.com/pavelkrolevets/go-ethereum/consensus"
- "github.com/pavelkrolevets/go-ethereum/consensus/ethash"
- "github.com/pavelkrolevets/go-ethereum/consensus/lcp"
"github.com/pavelkrolevets/go-ethereum/core"
"github.com/pavelkrolevets/go-ethereum/core/bloombits"
"github.com/pavelkrolevets/go-ethereum/core/rawdb"
@@ -49,6 +47,7 @@ import (
"github.com/pavelkrolevets/go-ethereum/params"
"github.com/pavelkrolevets/go-ethereum/rlp"
"github.com/pavelkrolevets/go-ethereum/rpc"
+ "github.com/pavelkrolevets/go-ethereum/consensus/lcp"
)
type LesServer interface {
@@ -65,6 +64,7 @@ type Ethereum struct {
// Channel for shutting down the service
shutdownChan chan bool // Channel for shutting down the Ethereum
+ stopDbUpgrade func() error // stop chain db sequential key upgrade
// Handlers
txPool *core.TxPool
@@ -87,6 +87,7 @@ type Ethereum struct {
miner *miner.Miner
gasPrice *big.Int
etherbase common.Address
+ coinbase common.Address
validator common.Address
periodBlock int64
maxValidators int64
@@ -98,6 +99,23 @@ type Ethereum struct {
lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)
}
+func (s *Ethereum) Validator() (validator common.Address, err error) {
+ s.lock.RLock()
+ validator = s.validator
+ s.lock.RUnlock()
+
+ if validator != (common.Address{}) {
+ return validator, nil
+ }
+ if wallets := s.AccountManager().Wallets(); len(wallets) > 0 {
+ if accounts := wallets[0].Accounts(); len(accounts) > 0 {
+ return accounts[0].Address, nil
+ }
+ }
+ return common.Address{}, fmt.Errorf("validator address must be explicitly specified")
+}
+
+
func (s *Ethereum) AddLesServer(ls LesServer) {
s.lesServer = ls
ls.SetBloomBitsIndexer(s.bloomIndexer)
@@ -116,6 +134,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
if err != nil {
return nil, err
}
+ stopDbUpgrade := upgradeDeduplicateData(chainDb)
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis)
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
return nil, genesisErr
@@ -128,11 +147,14 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
chainConfig: chainConfig,
eventMux: ctx.EventMux,
accountManager: ctx.AccountManager,
- engine: CreateConsensusEngine(ctx, &config.Ethash, chainConfig, chainDb),
+ engine: lcp.New(chainConfig.LCP, chainDb),
shutdownChan: make(chan bool),
+ stopDbUpgrade: stopDbUpgrade,
networkID: config.NetworkId,
gasPrice: config.GasPrice,
etherbase: config.Etherbase,
+ validator: config.Validator,
+ coinbase: config.Coinbase,
bloomRequests: make(chan chan *bloombits.Retrieval),
bloomIndexer: NewBloomIndexer(chainDb, params.BloomBitsBlocks),
}
@@ -213,37 +235,6 @@ func CreateDB(ctx *node.ServiceContext, config *Config, name string) (ethdb.Data
return db, nil
}
-// CreateConsensusEngine creates the required type of consensus engine instance for an Ethereum service
-func CreateConsensusEngine(ctx *node.ServiceContext, config *ethash.Config, chainConfig *params.ChainConfig, db ethdb.Database) consensus.Engine {
- // If LCP is requested, set it up
- if chainConfig.LCP != nil {
- return lcp.New(chainConfig.LCP, db)
- }
- // Otherwise assume proof-of-work
- switch config.PowMode {
- case ethash.ModeFake:
- log.Warn("Ethash used in fake mode")
- return ethash.NewFaker()
- case ethash.ModeTest:
- log.Warn("Ethash used in test mode")
- return ethash.NewTester()
- case ethash.ModeShared:
- log.Warn("Ethash used in shared mode")
- return ethash.NewShared()
- default:
- engine := ethash.New(ethash.Config{
- CacheDir: ctx.ResolvePath(config.CacheDir),
- CachesInMem: config.CachesInMem,
- CachesOnDisk: config.CachesOnDisk,
- DatasetDir: config.DatasetDir,
- DatasetsInMem: config.DatasetsInMem,
- DatasetsOnDisk: config.DatasetsOnDisk,
- })
- engine.SetThreads(-1) // Disable CPU mining
- return engine
- }
-}
-
// APIs return the collection of RPC services the ethereum package offers.
// NOTE, some of these services probably need to be moved to somewhere else.
func (s *Ethereum) APIs() []rpc.API {
@@ -337,19 +328,49 @@ func (s *Ethereum) SetEtherbase(etherbase common.Address) {
s.miner.SetEtherbase(etherbase)
}
-func (s *Ethereum) StartMining(local bool) error {
- eb, err := s.Etherbase()
- if err != nil {
- log.Error("Cannot start mining without etherbase", "err", err)
- return fmt.Errorf("etherbase missing: %v", err)
+// set in js console via admin interface or wrapper from cli flags
+func (self *Ethereum) SetValidator(validator common.Address) {
+ self.lock.Lock()
+ self.validator = validator
+ self.lock.Unlock()
+}
+
+func (s *Ethereum) Coinbase() (eb common.Address, err error) {
+ s.lock.RLock()
+ coinbase := s.coinbase
+ s.lock.RUnlock()
+
+ if coinbase != (common.Address{}) {
+ return coinbase, nil
}
- if clique, ok := s.engine.(*clique.Clique); ok {
- wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
+ if wallets := s.AccountManager().Wallets(); len(wallets) > 0 {
+ if accounts := wallets[0].Accounts(); len(accounts) > 0 {
+ return accounts[0].Address, nil
+ }
+ }
+ return common.Address{}, fmt.Errorf("coinbase address must be explicitly specified")
+}
+
+
+func (s *Ethereum) StartMining(local bool) error {
+ validator, err := s.Validator()
+ if err != nil {
+ log.Error("Cannot start mining without validator", "err", err)
+ return fmt.Errorf("validator missing: %v", err)
+ }
+ eb, err := s.Coinbase()
+ if err != nil {
+ log.Error("Cannot start mining without coinbase", "err", err)
+ return fmt.Errorf("coinbase missing: %v", err)
+ }
+
+ if lcp, ok := s.engine.(*lcp.LCP); ok {
+ wallet, err := s.accountManager.Find(accounts.Account{Address: validator})
if wallet == nil || err != nil {
- log.Error("Etherbase account unavailable locally", "err", err)
+ log.Error("Coinbase account unavailable locally", "err", err)
return fmt.Errorf("signer missing: %v", err)
}
- clique.Authorize(eb, wallet.SignHash)
+ lcp.Authorize(validator, wallet.SignHash)
}
if local {
// If local (CPU) mining is started, we can disable the transaction rejection
diff --git a/eth/config.go b/eth/config.go
index 6d726e62a5..a84b13fba1 100644
--- a/eth/config.go
+++ b/eth/config.go
@@ -96,6 +96,8 @@ type Config struct {
// Mining-related options
Etherbase common.Address `toml:",omitempty"`
+ Validator common.Address `toml:",omitempty"`
+ Coinbase common.Address `toml:",omitempty"`
MinerThreads int `toml:",omitempty"`
ExtraData []byte `toml:",omitempty"`
GasPrice *big.Int
diff --git a/eth/db_upgrade.go b/eth/db_upgrade.go
new file mode 100644
index 0000000000..094e741555
--- /dev/null
+++ b/eth/db_upgrade.go
@@ -0,0 +1,135 @@
+// Copyright 2016 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// Package eth implements the Ethereum protocol.
+package eth
+
+import (
+ "bytes"
+ "time"
+
+ "github.com/pavelkrolevets/go-ethereum/common"
+ "github.com/pavelkrolevets/go-ethereum/core"
+ "github.com/pavelkrolevets/go-ethereum/ethdb"
+ "github.com/pavelkrolevets/go-ethereum/log"
+ "github.com/pavelkrolevets/go-ethereum/rlp"
+)
+
+var deduplicateData = []byte("dbUpgrade_20170714deduplicateData")
+
+// upgradeDeduplicateData checks the chain database version and
+// starts a background process to make upgrades if necessary.
+// Returns a stop function that blocks until the process has
+// been safely stopped.
+func upgradeDeduplicateData(db ethdb.Database) func() error {
+ // If the database is already converted or empty, bail out
+ data, _ := db.Get(deduplicateData)
+ if len(data) > 0 && data[0] == 42 {
+ return nil
+ }
+ if data, _ := db.Get([]byte("LastHeader")); len(data) == 0 {
+ db.Put(deduplicateData, []byte{42})
+ return nil
+ }
+ // Start the deduplication upgrade on a new goroutine
+ log.Warn("Upgrading database to use lookup entries")
+ stop := make(chan chan error)
+
+ go func() {
+ // Create an iterator to read the entire database and covert old lookup entires
+ it := db.(*ethdb.LDBDatabase).NewIterator()
+ defer func() {
+ if it != nil {
+ it.Release()
+ }
+ }()
+
+ var (
+ converted uint64
+ failed error
+ )
+ for failed == nil && it.Next() {
+ // Skip any entries that don't look like old transaction meta entires (0x01)
+ key := it.Key()
+ if len(key) != common.HashLength+1 || key[common.HashLength] != 0x01 {
+ continue
+ }
+ // Skip any entries that don't contain metadata (name clash between 0x01 and )
+ var meta struct {
+ BlockHash common.Hash
+ BlockIndex uint64
+ Index uint64
+ }
+ if err := rlp.DecodeBytes(it.Value(), &meta); err != nil {
+ continue
+ }
+ // Skip any already upgraded entries (clash due to ending with 0x01 (old suffix))
+ hash := key[:common.HashLength]
+
+ if hash[0] == byte('l') {
+ // Potential clash, the "old" `hash` must point to a live transaction.
+ if tx, _, _, _ := core.GetTransaction(db, common.BytesToHash(hash)); tx == nil || !bytes.Equal(tx.Hash().Bytes(), hash) {
+ continue
+ }
+ }
+ // Convert the old metadata to a new lookup entry, delete duplicate data
+ if failed = db.Put(append([]byte("l"), hash...), it.Value()); failed == nil { // Write the new looku entry
+ if failed = db.Delete(hash); failed == nil { // Delete the duplicate transaction data
+ if failed = db.Delete(append([]byte("receipts-"), hash...)); failed == nil { // Delete the duplicate receipt data
+ if failed = db.Delete(key); failed != nil { // Delete the old transaction metadata
+ break
+ }
+ }
+ }
+ }
+ // Bump the conversion counter, and recreate the iterator occasionally to
+ // avoid too high memory consumption.
+ converted++
+ if converted%100000 == 0 {
+ it.Release()
+ it = db.(*ethdb.LDBDatabase).NewIterator()
+ it.Seek(key)
+
+ log.Info("Deduplicating database entries", "deduped", converted)
+ }
+ // Check for termination, or continue after a bit of a timeout
+ select {
+ case errc := <-stop:
+ errc <- nil
+ return
+ case <-time.After(time.Microsecond * 100):
+ }
+ }
+ // Upgrade finished, mark a such and terminate
+ if failed == nil {
+ log.Info("Database deduplication successful", "deduped", converted)
+ db.Put(deduplicateData, []byte{42})
+ } else {
+ log.Error("Database deduplication failed", "deduped", converted, "err", failed)
+ }
+ it.Release()
+ it = nil
+
+ errc := <-stop
+ errc <- failed
+ }()
+ // Assembly the cancellation callback
+ return func() error {
+ errc := make(chan error)
+ stop <- errc
+ return <-errc
+ }
+}
diff --git a/miner/worker.go b/miner/worker.go
index 0f605bed6d..4c947b256d 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -64,7 +64,7 @@ type Agent interface {
type Work struct {
config *params.ChainConfig
signer types.Signer
-
+ LCPContext *types.LCPContext
state *state.StateDB // apply state changes here
ancestors mapset.Set // ancestor set (used for checking uncle parent validity)
family mapset.Set // family set (used for checking uncle invalidity)
@@ -79,6 +79,7 @@ type Work struct {
receipts []*types.Receipt
createdAt time.Time
+
}
type Result struct {
@@ -620,10 +621,11 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, coinbase common.Address, gp *core.GasPool) (error, []*types.Log) {
snap := env.state.Snapshot()
-
- receipt, _, err := core.ApplyTransaction(env.config, bc, &coinbase, gp, env.state, env.header, tx, &env.header.GasUsed, vm.Config{})
+ LcpSnap := env.LCPContext.Snapshot()
+ receipt, _, err := core.ApplyTransaction(env.config, env.LCPContext, bc, &coinbase, gp, env.state, env.header, tx, &env.header.GasUsed, vm.Config{})
if err != nil {
env.state.RevertToSnapshot(snap)
+ env.LCPContext.RevertToSnapShot(LcpSnap)
return err, nil
}
env.txs = append(env.txs, tx)