mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
ADDED LCP engine
This commit is contained in:
parent
0e2486f4fc
commit
92e4d96935
10 changed files with 244 additions and 80 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"`
|
||||
|
|
|
|||
107
eth/backend.go
107
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()
|
||||
}
|
||||
if clique, ok := s.engine.(*clique.Clique); ok {
|
||||
wallet, err := s.accountManager.Find(accounts.Account{Address: eb})
|
||||
|
||||
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 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
135
eth/db_upgrade.go
Normal file
135
eth/db_upgrade.go
Normal file
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
// 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 (<hash>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 <hash>0x01 and <some-prefix><hash>)
|
||||
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 <hash> 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue