From e639f0f46e109b43b67e2068ad68981419d1fde5 Mon Sep 17 00:00:00 2001 From: DinhLN Date: Tue, 22 Jan 2019 10:49:16 +0700 Subject: [PATCH 1/6] Fixed check penalty signers working when it return chain. --- eth/backend.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/eth/backend.go b/eth/backend.go index 1e86f96829..7a649d9c53 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -274,6 +274,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { start := time.Now() prevHeader := chain.GetHeaderByNumber(prevEpoc) penSigners := c.GetMasternodes(chain, prevHeader) + goodSigners := make(map[common.Address]*big.Int) if len(penSigners) > 0 { // Loop for each block to check missing sign. for i := prevEpoc; i < blockNumberEpoc; i++ { @@ -282,25 +283,33 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { bhash := bheader.Hash() block := chain.GetBlock(bhash, i) if len(penSigners) > 0 { - signedMasternodes, err := contracts.GetSignersFromContract(canonicalState, block) + signer, err := c.RecoverSigner(block.Header()) if err != nil { return nil, err } - if len(signedMasternodes) > 0 { - // Check signer signed? - for _, signed := range signedMasternodes { - for j, addr := range penSigners { - if signed == addr { - // Remove it from dupSigners. - penSigners = append(penSigners[:j], penSigners[j+1:]...) - } - } + for _, addr := range penSigners { + if signer == addr { + // Remove it from dupSigners. + goodSigners[signer] = goodSigners[signer].Add(goodSigners[signer], big.NewInt(1)) } } } else { break } } + + if len(goodSigners) > 0 { + for signer, totalSign := range goodSigners { + if totalSign.Cmp(big.NewInt(4)) >= 0 { + for j, addr := range penSigners { + if signer == addr { + // Remove it from dupSigners. + penSigners = append(penSigners[:j], penSigners[j+1:]...) + } + } + } + } + } } } log.Debug("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) From 87473423731708518990379bd3ea28d2f5a71aba Mon Sep 17 00:00:00 2001 From: DinhLN Date: Tue, 29 Jan 2019 14:53:53 +0700 Subject: [PATCH 2/6] Fixed check penalty using block creator instead of using block signer transaction. --- common/constants.go | 1 + contracts/utils.go | 103 ++++++++++++++++++++++++++------------------ eth/backend.go | 43 +++++++++++++++--- 3 files changed, 98 insertions(+), 49 deletions(-) diff --git a/common/constants.go b/common/constants.go index 6b483d9b2c..8ca2ec3eca 100644 --- a/common/constants.go +++ b/common/constants.go @@ -18,6 +18,7 @@ const ( LimitThresholdNonceInQueue = 10 DefaultMinGasPrice = 2500 MergeSignRange = 15 + RangeReturnSigner = 90 ) var TIP2019Block = big.NewInt(1050000) diff --git a/contracts/utils.go b/contracts/utils.go index 1146f4208c..7dbf205a53 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -306,6 +306,62 @@ func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte) return random, nil } +// Get txw signed for block using cache or block body inside. +func GetSignersSignedAtBlockHash(c *posv.Posv, chain consensus.ChainReader, data map[common.Hash][]common.Address, header *types.Header, curNumber uint64) map[common.Hash][]common.Address { + if signData, ok := c.BlockSigners.Get(header.Hash()); ok { + txs := signData.([]*types.Transaction) + for _, tx := range txs { + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + data[blkHash] = append(data[blkHash], from) + } + } else { + log.Debug("Failed get from cached", "hash", header.Hash().String(), "number", curNumber) + block := chain.GetBlock(header.Hash(), curNumber) + txs := block.Transactions() + receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), curNumber) + + var signTxs []*types.Transaction + for _, tx := range txs { + if tx.IsSigningTransaction() { + var b uint + for _, r := range receipts { + if r.TxHash == tx.Hash() { + if len(r.PostState) > 0 { + b = types.ReceiptStatusSuccessful + } else { + b = r.Status + } + break + } + } + + if b == types.ReceiptStatusFailed { + continue + } + + signTxs = append(signTxs, tx) + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + data[blkHash] = append(data[blkHash], from) + } + } + c.BlockSigners.Add(header.Hash(), signTxs) + } + + return data +} + +// Get signers list from bytes. +func GetSignersFromBytes(byteHeader []byte) []common.Address { + signers := make([]common.Address, len(byteHeader)/common.AddressLength) + for i := 0; i < len(masternodes); i++ { + copy(signers[i][:], byteHeader[i*common.AddressLength:]) + } + + return signers +} + // Calculate reward for reward checkpoint. func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, header *types.Header, rCheckpoint uint64, totalSigner *uint64) (map[common.Address]*rewardLog, error) { // Not reward for singer of genesis block and only calculate reward at checkpoint block. @@ -317,49 +373,10 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, header *t mapBlkHash := map[uint64]common.Hash{} data := make(map[common.Hash][]common.Address) - for i := prevCheckpoint + (rCheckpoint * 2) - 1; i >= startBlockNumber; i-- { - header = chain.GetHeader(header.ParentHash, i) - mapBlkHash[i] = header.Hash() - if signData, ok := c.BlockSigners.Get(header.Hash()); ok { - txs := signData.([]*types.Transaction) - for _, tx := range txs { - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() - data[blkHash] = append(data[blkHash], from) - } - } else { - log.Debug("Failed get from cached", "hash", header.Hash().String(), "number", i) - block := chain.GetBlock(header.Hash(), i) - txs := block.Transactions() - receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i) - - var signTxs []*types.Transaction - for _, tx := range txs { - if tx.IsSigningTransaction() { - var b uint - for _, r := range receipts { - if r.TxHash == tx.Hash() { - if len(r.PostState) > 0 { - b = types.ReceiptStatusSuccessful - } else { - b = r.Status - } - break - } - } - - if b == types.ReceiptStatusFailed { - continue - } - - signTxs = append(signTxs, tx) - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() - data[blkHash] = append(data[blkHash], from) - } - } - c.BlockSigners.Add(header.Hash(), signTxs) - } + for curNumber := prevCheckpoint + (rCheckpoint * 2) - 1; curNumber >= startBlockNumber; curNumber-- { + header = chain.GetHeader(header.ParentHash, curNumber) + mapBlkHash[curNumber] = header.Hash() + data = GetSignersSignedAtBlockHash(c, chain, data, header, curNumber) } header = chain.GetHeader(header.ParentHash, prevCheckpoint) masternodes := posv.GetMasternodesFromCheckpointHeader(header) diff --git a/eth/backend.go b/eth/backend.go index 7a649d9c53..9a2f121394 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -274,7 +274,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { start := time.Now() prevHeader := chain.GetHeaderByNumber(prevEpoc) penSigners := c.GetMasternodes(chain, prevHeader) - goodSigners := make(map[common.Address]*big.Int) + signedSigners := make(map[common.Address]*big.Int) if len(penSigners) > 0 { // Loop for each block to check missing sign. for i := prevEpoc; i < blockNumberEpoc; i++ { @@ -289,8 +289,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } for _, addr := range penSigners { if signer == addr { - // Remove it from dupSigners. - goodSigners[signer] = goodSigners[signer].Add(goodSigners[signer], big.NewInt(1)) + signedSigners[signer] = signedSigners[signer].Add(signedSigners[signer], big.NewInt(1)) } } } else { @@ -298,12 +297,12 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } } - if len(goodSigners) > 0 { - for signer, totalSign := range goodSigners { + if len(signedSigners) > 0 { + for signer, totalSign := range signedSigners { if totalSign.Cmp(big.NewInt(4)) >= 0 { for j, addr := range penSigners { if signer == addr { - // Remove it from dupSigners. + // If create block above 4 times then remove it from penSigners. penSigners = append(penSigners[:j], penSigners[j+1:]...) } } @@ -312,6 +311,38 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } } } + + // Check penalty signer return chain. + prevSigners := contracts.GetSignersFromBytes(prevHeader.Penalties) + if len(prevSigners) > 0 { + startCheck := blockNumberEpoc - common.RangeReturnSigner + data := make(map[common.Hash][]common.Address) + mapBlkHash := map[uint64]common.Hash{} + for curNumber := startCheck; curNumber < blockNumberEpoc; curNumber++ { + signers := make(map[common.Hash][]common.Address) + header := chain.GetHeaderByNumber(curNumber) + mapBlkHash[curNumber] = header.Hash() + data = contracts.GetSignersSignedAtBlockHash(c, chain, signers, header, curNumber) + } + + for _, blkHash := range mapBlkHash { + signers := data[blkHash] + for j, addr := range prevSigners { + for _, signer := range signers { + if signer == addr { + // If create block above 4 times then remove it from penSigners. + prevSigners = append(prevSigners[:j], prevSigners[j+1:]...) + } + } + } + } + if len(prevSigners) > 0 { + for _, signer := range prevSigners { + penSigners = append(penSigners, signer) + } + } + } + log.Debug("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) return penSigners, nil } From cafef440747892e403052fe255025463eef90f58 Mon Sep 17 00:00:00 2001 From: DinhLN Date: Fri, 22 Feb 2019 10:27:22 +0700 Subject: [PATCH 3/6] Fixed minor bug for get signers from penalties header. --- contracts/utils.go | 2 +- core/state_transition.go | 2 +- eth/backend.go | 4 +--- internal/ethapi/api.go | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/contracts/utils.go b/contracts/utils.go index 7dbf205a53..d664471501 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -355,7 +355,7 @@ func GetSignersSignedAtBlockHash(c *posv.Posv, chain consensus.ChainReader, data // Get signers list from bytes. func GetSignersFromBytes(byteHeader []byte) []common.Address { signers := make([]common.Address, len(byteHeader)/common.AddressLength) - for i := 0; i < len(masternodes); i++ { + for i := 0; i < len(signers); i++ { copy(signers[i][:], byteHeader[i*common.AddressLength:]) } diff --git a/core/state_transition.go b/core/state_transition.go index 1a5f6c0fd0..2fb9893d00 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -238,7 +238,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo contractAction = "contract creation" } else { // Increment the nonce for the next transaction - nonce = st.state.GetNonce(sender.Address())+1 + nonce = st.state.GetNonce(sender.Address()) + 1 st.state.SetNonce(sender.Address(), nonce) ret, st.gas, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value) contractAction = "contract call" diff --git a/eth/backend.go b/eth/backend.go index 9a2f121394..514186692d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -337,9 +337,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } } if len(prevSigners) > 0 { - for _, signer := range prevSigners { - penSigners = append(penSigners, signer) - } + penSigners = append(penSigners, prevSigners...) } } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index cda2f037ac..59f59972e5 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -683,7 +683,7 @@ func (s *PublicBlockChainAPI) GetMasternodes(b *types.Block, ctx context.Context if prevCheckpointBlock != nil { masternodes = engine.GetMasternodesFromCheckpointHeader(prevCheckpointBlock.Header(), curBlockNumber, s.b.ChainConfig().Posv.Epoch) } - } else { + } else { log.Error("Undefined POSV consensus engine") } } @@ -980,7 +980,7 @@ func (s *PublicBlockChainAPI) rpcOutputBlockSigners(b *types.Block, ctx context. } } } - } else { + } else { log.Error("Undefined POSV consensus engine") } } From 3fb5566726ef0bde10af656ecd44ea333caeedb7 Mon Sep 17 00:00:00 2001 From: Nguyen Ba Tam Date: Thu, 24 Jan 2019 10:23:09 +0700 Subject: [PATCH 4/6] remove run evm with signing tracsaction --- common/constants.go | 3 +- consensus/posv/posv.go | 49 ++++++++++++++----- contracts/utils.go | 25 ++++++++-- core/blockchain.go | 7 ++- core/state/statedb.go | 8 +++ core/state_processor.go | 44 +++++++++++++++++ eth/backend.go | 55 ++++++++++++++++++++- internal/ethapi/api.go | 106 ++++++++++++++++++++++++++++++---------- miner/worker.go | 15 ++++++ params/config.go | 4 ++ 10 files changed, 272 insertions(+), 44 deletions(-) diff --git a/common/constants.go b/common/constants.go index 8ca2ec3eca..701a252eb9 100644 --- a/common/constants.go +++ b/common/constants.go @@ -22,7 +22,8 @@ const ( ) var TIP2019Block = big.NewInt(1050000) -var IsTestnet = false +var TIPEVMSignerBlock = big.NewInt(2500000) +var IsTestnet bool = false var StoreRewardFolder string var RollbackHash Hash var MinGasPrice int64 diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 7817cbc7db..3ccdb81419 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -225,11 +225,12 @@ type Posv struct { signFn clique.SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields - BlockSigners *lru.Cache - HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{}) - HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) - HookValidator func(header *types.Header, signers []common.Address) ([]byte, error) - HookVerifyMNs func(header *types.Header, signers []common.Address) error + BlockSigners *lru.Cache + HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{}) + HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) + HookPenaltyTIPEVM func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) + HookValidator func(header *types.Header, signers []common.Address) ([]byte, error) + HookVerifyMNs func(header *types.Header, signers []common.Address) error } // New creates a PoSV proof-of-stake-voting consensus engine with the initial @@ -398,8 +399,14 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types. // If the block is a checkpoint block, verify the signer list if number%c.config.Epoch == 0 { penPenalties := []common.Address{} - if c.HookPenalty != nil { - penPenalties, err = c.HookPenalty(chain, number) + if c.HookPenalty != nil || c.HookPenaltyTIPEVM != nil { + var penPenalties []common.Address = nil + var err error = nil + if chain.Config().IsTIPEVMSigner(header.Number) { + penPenalties, err = c.HookPenaltyTIPEVM(chain, number) + } else { + penPenalties, err = c.HookPenalty(chain, number) + } if err != nil { return err } @@ -788,8 +795,14 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error header.Extra = header.Extra[:extraVanity] masternodes := snap.GetSigners() if number >= c.config.Epoch && number%c.config.Epoch == 0 { - if c.HookPenalty != nil { - penMasternodes, err := c.HookPenalty(chain, number) + if c.HookPenalty != nil || c.HookPenaltyTIPEVM != nil { + var penMasternodes []common.Address = nil + var err error = nil + if chain.Config().IsTIPEVMSigner(header.Number) { + penMasternodes, err = c.HookPenaltyTIPEVM(chain, number) + } else { + penMasternodes, err = c.HookPenalty(chain, number) + } if err != nil { return err } @@ -1036,8 +1049,8 @@ func (c *Posv) GetMasternodesFromCheckpointHeader(preCheckpointHeader *types.Hea return masternodes } -func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) error { - var signTxs []*types.Transaction +func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipts []*types.Receipt) []*types.Transaction { + signTxs := []*types.Transaction{} for _, tx := range txs { if tx.IsSigningTransaction() { var b uint @@ -1063,7 +1076,19 @@ func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipt log.Debug("Save tx signers to cache", "hash", header.Hash().String(), "number", header.Number, "len(txs)", len(signTxs)) c.BlockSigners.Add(header.Hash(), signTxs) - return nil + return signTxs +} + +func (c *Posv) CacheSigner(header *types.Header, txs []*types.Transaction) []*types.Transaction { + signTxs := []*types.Transaction{} + for _, tx := range txs { + if tx.IsSigningTransaction() { + signTxs = append(signTxs, tx) + } + } + log.Debug("Save tx signers to cache", "hash", header.Hash().String(), "number", header.Number, "len(txs)", len(signTxs)) + c.BlockSigners.Add(header.Hash(), signTxs) + return signTxs } func (c *Posv) GetDb() ethdb.Database { diff --git a/contracts/utils.go b/contracts/utils.go index d664471501..dfe20de790 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -373,10 +373,27 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, header *t mapBlkHash := map[uint64]common.Hash{} data := make(map[common.Hash][]common.Address) - for curNumber := prevCheckpoint + (rCheckpoint * 2) - 1; curNumber >= startBlockNumber; curNumber-- { - header = chain.GetHeader(header.ParentHash, curNumber) - mapBlkHash[curNumber] = header.Hash() - data = GetSignersSignedAtBlockHash(c, chain, data, header, curNumber) + for i := prevCheckpoint + (rCheckpoint * 2) - 1; i >= startBlockNumber; i-- { + header = chain.GetHeader(header.ParentHash, i) + mapBlkHash[i] = header.Hash() + signData, ok := c.BlockSigners.Get(header.Hash()) + if !ok { + log.Debug("Failed get from cached", "hash", header.Hash().String(), "number", i) + block := chain.GetBlock(header.Hash(), i) + txs := block.Transactions() + if !chain.Config().IsTIPEVMSigner(header.Number) { + receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i) + signData = c.CacheData(header, txs, receipts); + } else { + signData = c.CacheSigner(header, txs); + } + } + txs := signData.([]*types.Transaction) + for _, tx := range txs { + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + data[blkHash] = append(data[blkHash], from) + } } header = chain.GetHeader(header.ParentHash, prevCheckpoint) masternodes := posv.GetMasternodesFromCheckpointHeader(header) diff --git a/core/blockchain.go b/core/blockchain.go index 2f0dc16531..ae4536bcaf 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -507,7 +507,7 @@ func (bc *BlockChain) insert(block *types.Block) { bc.currentBlock.Store(block) // save cache BlockSigners - if bc.chainConfig.Posv != nil { + if bc.chainConfig.Posv != nil && !bc.chainConfig.IsTIPEVMSigner(block.Number()) { engine := bc.Engine().(*posv.Posv) engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash())) } @@ -1019,6 +1019,11 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. if status == CanonStatTy { bc.insert(block) } + // save cache BlockSigners + if bc.chainConfig.Posv != nil && bc.chainConfig.IsTIPEVMSigner(block.Number()) { + engine := bc.Engine().(*posv.Posv) + engine.CacheSigner(block.Header(), block.Transactions()) + } bc.futureBlocks.Remove(block.Hash()) return status, nil } diff --git a/core/state/statedb.go b/core/state/statedb.go index bd67e789d5..2ae700cd67 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -357,6 +357,14 @@ func (self *StateDB) deleteStateObject(stateObject *stateObject) { self.setError(self.trie.TryDelete(addr[:])) } +// DeleteAddress removes the address from the state trie. +func (self *StateDB) DeleteAddress(addr common.Address) { + stateObject := self.getStateObject(addr) + if stateObject != nil && !stateObject.deleted { + self.deleteStateObject(stateObject) + } +} + // Retrieve a state object given my the address. Returns nil if not found. func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) { // Prefer 'live' objects. diff --git a/core/state_processor.go b/core/state_processor.go index 6ec3fcc6f1..d21ecd70f4 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -73,6 +73,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } + if p.config.IsTIPEVMSigner(header.Number) { + statedb.DeleteAddress(common.HexToAddress(common.BlockSigners)) + } InitSignerInTransactions(p.config, header, block.Transactions()) for i, tx := range block.Transactions() { statedb.Prepare(tx.Hash(), block.Hash(), i) @@ -101,6 +104,9 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } + if p.config.IsTIPEVMSigner(header.Number) { + statedb.DeleteAddress(common.HexToAddress(common.BlockSigners)) + } if cBlock.stop { return nil, nil, 0, ErrStopPreparingBlock } @@ -132,6 +138,9 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) { + if tx.To() != nil && tx.To().String() == common.BlockSigners && config.IsTIPEVMSigner(header.Number) { + return ApplySignTransaction(config, statedb, header, tx, usedGas) + } msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { return nil, 0, err @@ -171,6 +180,41 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common return receipt, gas, err } +func ApplySignTransaction(config *params.ChainConfig, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, uint64, error) { + // Update the state with pending changes + var root []byte + if config.IsByzantium(header.Number) { + statedb.Finalise(true) + } else { + root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() + } + from, err := types.Sender(types.MakeSigner(config, header.Number), tx) + if err != nil { + return nil, 0, err + } + nonce := statedb.GetNonce(from) + if nonce < tx.Nonce() { + return nil, 0, ErrNonceTooHigh + } else if nonce > tx.Nonce() { + return nil, 0, ErrNonceTooLow + } + statedb.SetNonce(from, nonce+1) + // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx + // based on the eip phase, we're passing wether the root touch-delete accounts. + receipt := types.NewReceipt(root, false, *usedGas) + receipt.TxHash = tx.Hash() + receipt.GasUsed = 0 + // if the transaction created a contract, store the creation address in the receipt. + // Set the receipt logs and create a bloom for filtering + log := &types.Log{} + log.Address = common.HexToAddress(common.BlockSigners) + log.BlockNumber = header.Number.Uint64() + statedb.AddLog(log) + receipt.Logs = statedb.GetLogs(tx.Hash()) + receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + return receipt, 0, nil +} + func InitSignerInTransactions(config *params.ChainConfig, header *types.Header, txs types.Transactions) { nWorker := runtime.NumCPU() signer := types.MakeSigner(config, header.Number) diff --git a/eth/backend.go b/eth/backend.go index 514186692d..87896b32cf 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -20,6 +20,7 @@ package eth import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/core/state" "math/big" "runtime" "sync" @@ -36,7 +37,6 @@ import ( "github.com/ethereum/go-ethereum/contracts" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/bloombits" - "github.com/ethereum/go-ethereum/core/state" //"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -347,6 +347,59 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { return []common.Address{}, nil } + // Hook scans for bad masternodes and decide to penalty them + c.HookPenaltyTIPEVM = func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) { + canonicalState, err := eth.blockchain.State() + if canonicalState == nil || err != nil { + log.Crit("Can't get state at head of canonical chain", "head number", eth.blockchain.CurrentHeader().Number.Uint64(), "err", err) + } + prevEpoc := blockNumberEpoc - chain.Config().Posv.Epoch + if prevEpoc >= 0 { + start := time.Now() + prevHeader := chain.GetHeaderByNumber(prevEpoc) + penSigners := c.GetMasternodes(chain, prevHeader) + if len(penSigners) > 0 { + // Loop for each block to check missing sign. + blockHash := map[common.Hash]bool{} + for i := prevEpoc; i < blockNumberEpoc; i++ { + if len(penSigners) > 0 { + bheader := chain.GetHeaderByNumber(i) + bhash := bheader.Hash() + if i%common.MergeSignRange == 0 { + blockHash[bhash] = true + } + signData, ok := c.BlockSigners.Get(bhash) + if !ok { + block := chain.GetBlock(bhash, i) + txs := block.Transactions() + signData = c.CacheSigner(bheader, txs); + } + txs := signData.([]*types.Transaction) + // Check signer signed? + for _, tx := range txs { + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + if blockHash[blkHash] == true { + for j, addr := range penSigners { + if from == addr { + // Remove it from dupSigners. + penSigners = append(penSigners[:j], penSigners[j+1:]...) + break + } + } + } + } + } else { + break + } + } + } + log.Debug("Time Calculated HookPenaltyTIPEVM ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) + return penSigners, nil + } + return []common.Address{}, nil + } + // Hook calculates reward for masternodes c.HookReward = func(chain consensus.ChainReader, stateBlock *state.StateDB, header *types.Header) (error, map[string]interface{}) { parentHeader := eth.blockchain.GetHeader(header.ParentHash, header.Number.Uint64()-1) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 59f59972e5..dd9928d47b 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -950,33 +950,40 @@ func (s *PublicBlockChainAPI) rpcOutputBlockSigners(b *types.Block, ctx context. var signers []common.Address var filterSigners []common.Address if b.Number().Int64() > 0 { - curBlockNumber := b.Number().Uint64() - prevBlockNumber := curBlockNumber + (common.MergeSignRange - (curBlockNumber % common.MergeSignRange)) - latestBlockNumber := s.b.CurrentBlock().Number().Uint64() - if prevBlockNumber >= latestBlockNumber || !s.b.ChainConfig().IsTIP2019(b.Number()) { - prevBlockNumber = curBlockNumber + blockNumber := b.Number().Uint64() + signedBlockNumber := blockNumber + (common.MergeSignRange - (blockNumber % common.MergeSignRange)) + latestBlockNumber := s.b.CurrentBlock().Number() + if signedBlockNumber >= latestBlockNumber.Uint64() || !s.b.ChainConfig().IsTIP2019(b.Number()) { + signedBlockNumber = blockNumber } if engine, ok := s.b.GetEngine().(*posv.Posv); ok { - prevBlock, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(prevBlockNumber)) - if err != nil { - log.Error("Fail to get previous block", "error", err) - return []common.Address{}, err - } - addrBlockSigner := common.HexToAddress(common.BlockSigners) - signers, err = contracts.GetSignersByExecutingEVM(addrBlockSigner, client, prevBlock.Hash()) - if err != nil { - log.Error("Fail to get signers from block signer SC.", "error", err) - return []common.Address{}, err - } - validator, _ := engine.RecoverValidator(b.Header()) - creator, _ := engine.RecoverSigner(b.Header()) - signers = append(signers, validator) - signers = append(signers, creator) - for _, masternode := range masternodes { - for _, signer := range signers { - if signer == masternode { - filterSigners = append(filterSigners, masternode) - break + // Get block epoc latest. + lastCheckpointNumber := signedBlockNumber - (signedBlockNumber % s.b.ChainConfig().Posv.Epoch) + prevCheckpointBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(lastCheckpointNumber)) + if prevCheckpointBlock != nil { + masternodes := engine.GetMasternodesFromCheckpointHeader(prevCheckpointBlock.Header(), blockNumber, s.b.ChainConfig().Posv.Epoch) + signedBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(signedBlockNumber)) + if s.b.ChainConfig().IsTIPEVMSigner(latestBlockNumber) { + signers, err = GetSignersFromBlocks(s.b, signedBlock.NumberU64(), signedBlock.Hash(), masternodes) + } else { + signers, err = contracts.GetSignersByExecutingEVM(common.HexToAddress(common.BlockSigners), client, signedBlock.Hash()) + } + if err != nil { + log.Error("Fail to get signers from block signer SC.", "error", err) + return nil, err + } + validator, _ := engine.RecoverValidator(b.Header()) + creator, _ := engine.RecoverSigner(b.Header()) + signers = append(signers, validator) + signers = append(signers, creator) + countFinality := 0 + for _, masternode := range masternodes { + for _, signer := range signers { + if signer == masternode { + countFinality++ + filterSigners = append(filterSigners, masternode) + break + } } } } @@ -1618,3 +1625,52 @@ func (s *PublicNetAPI) PeerCount() hexutil.Uint { func (s *PublicNetAPI) Version() string { return fmt.Sprintf("%d", s.networkVersion) } + +func GetSignersFromBlocks(b Backend, blockNumber uint64, blockHash common.Hash, masternodes []common.Address) ([]common.Address, error) { + var addrs []common.Address + mapMN := map[common.Address]bool{} + for _, node := range masternodes { + mapMN[node] = true + } + if engine, ok := b.GetEngine().(*posv.Posv); ok { + limitNumber := blockNumber - blockNumber%b.ChainConfig().Posv.Epoch + 2*b.ChainConfig().Posv.Epoch - 1 + currentNumber := b.CurrentBlock().NumberU64() + if limitNumber > currentNumber { + limitNumber = currentNumber + } + for i := blockNumber + 1; i <= limitNumber; i++ { + header, err := b.HeaderByNumber(nil, rpc.BlockNumber(i)) + if err != nil { + return addrs, err + } + signData, ok := engine.BlockSigners.Get(header.Hash()) + var signTxs []*types.Transaction = nil + if !ok { + blockData, err := b.BlockByNumber(nil, rpc.BlockNumber(i)) + if err != nil { + return addrs, err + } + signTxs = []*types.Transaction{} + for _, tx := range blockData.Transactions() { + if tx.IsSigningTransaction() { + signTxs = append(signTxs, tx) + } + } + } else { + signTxs = signData.([]*types.Transaction) + } + for _, signtx := range signTxs { + blkHash := common.BytesToHash(signtx.Data()[len(signtx.Data())-32:]) + from := *signtx.From() + if blkHash == blockHash && mapMN[from] == true { + addrs = append(addrs, from) + delete(mapMN, from) + } + } + if len(mapMN) == 0 { + break + } + } + } + return addrs, nil +} diff --git a/miner/worker.go b/miner/worker.go index 8159e41547..91ee30df56 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -18,6 +18,7 @@ package miner import ( "bytes" + "encoding/binary" "fmt" "math/big" "os" @@ -583,6 +584,9 @@ func (self *worker) commitNewWork() { if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 { misc.ApplyDAOHardFork(work.state) } + if self.config.IsTIPEVMSigner(header.Number) { + work.state.DeleteAddress(common.HexToAddress(common.BlockSigners)) + } // won't grasp txs at checkpoint var ( txs *types.TransactionsByPriceAndNonce @@ -671,6 +675,17 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB log.Trace("Ignoring reply protected special transaction", "hash", tx.Hash(), "eip155", env.config.EIP155Block) continue } + if tx.To().Hex() == common.BlockSigners { + if len(tx.Data()) < 68 { + log.Trace("Data special transaction invalid lenght", "hash", tx.Hash(), "data", len(tx.Data())) + continue + } + blkNumber := binary.BigEndian.Uint64(tx.Data()[8:40]) + if blkNumber >= env.header.Number.Uint64() || blkNumber <= env.header.Number.Uint64()-env.config.Posv.Epoch*2 { + log.Trace("Data special transaction invalid number", "hash", tx.Hash(), "blkNumber", blkNumber, "miner", env.header.Number) + continue + } + } // Start executing the transaction env.state.Prepare(tx.Hash(), common.Hash{}, env.tcount) nonce := env.state.GetNonce(from) diff --git a/params/config.go b/params/config.go index 5a3c194d0a..a8f4027109 100644 --- a/params/config.go +++ b/params/config.go @@ -217,6 +217,10 @@ func (c *ChainConfig) IsTIP2019(num *big.Int) bool { return isForked(common.TIP2019Block, num) } +func (c *ChainConfig) IsTIPEVMSigner(num *big.Int) bool { + return isForked(common.TIPEVMSignerBlock, num) +} + // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice). // // The returned GasTable's fields shouldn't, under any circumstances, be changed. From e90141a3baa029819161949272adf190d64bd4cd Mon Sep 17 00:00:00 2001 From: Nguyen Ba Tam Date: Wed, 30 Jan 2019 15:45:46 +0700 Subject: [PATCH 5/6] clean all state of block signer --- cmd/tomoclean/main.go | 273 ++++++++++++++++++++++++++++++++++++++++++ cmd/utils/flags.go | 8 +- trie/hasher.go | 54 ++++----- trie/iterator.go | 22 ++-- trie/node.go | 78 ++++++------ trie/proof.go | 24 ++-- trie/sync.go | 12 +- trie/trie.go | 76 ++++++------ trie/trie_test.go | 10 +- 9 files changed, 415 insertions(+), 142 deletions(-) create mode 100644 cmd/tomoclean/main.go diff --git a/cmd/tomoclean/main.go b/cmd/tomoclean/main.go new file mode 100644 index 0000000000..991339ee66 --- /dev/null +++ b/cmd/tomoclean/main.go @@ -0,0 +1,273 @@ +package main + +import ( + "flag" + "fmt" + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie" + "github.com/hashicorp/golang-lru" + "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/util" + "os" + "os/signal" + "runtime" + "sync" + "sync/atomic" + "time" +) + +var ( + dir = flag.String("dir", "", "dir to mainet chain data") + cacheSize = flag.Int("size", 1000000, "dir to mainet chain data") + file = flag.String("file", "", "dir to mainet chain data") +) + +type StateNode struct { + node trie.Node + path []byte +} +type ResultProcessNode struct { + index int + number int + newNodes [17]*StateNode + keys [17]*[]byte +} + +var sercureKey = []byte("secure-key-") +var nWorker = runtime.NumCPU() / 2 +var cleanAddress = []common.Address{common.HexToAddress(common.BlockSigners)} +var cache *lru.Cache +var finish = int32(0) +var running = true +var stateRoots = make(chan *trie.SecureTrie) + +func main() { + flag.Parse() + lddb, _ := ethdb.NewLDBDatabase(*dir, eth.DefaultConfig.DatabaseCache, utils.MakeDatabaseHandles()) + head := core.GetHeadBlockHash(lddb) + currentHeader := core.GetHeader(lddb, head, core.GetBlockNumber(lddb, head)) + tridb := trie.NewDatabase(lddb) + catchEventInterupt(lddb.LDB()) + cache, _ = lru.New(*cacheSize) + go func() { + for i := uint64(1); i <= currentHeader.Number.Uint64(); i++ { + hash := core.GetCanonicalHash(lddb, i) + root := core.GetHeader(lddb, hash, i).Root + trieRoot, err := trie.NewSecure(root, tridb, 0) + if err != nil { + continue + } + fmt.Println(time.Now().Format(time.RFC3339), "Found a trie state root at block ", i, "state root ", root.Hex()) + if running { + stateRoots <- trieRoot + }else { + break + } + } + if running { + close(stateRoots) + } + }() + for trieRoot := range stateRoots { + atomic.StoreInt32(&finish, 1) + if running { + for _, address := range cleanAddress { + enc := trieRoot.Get(address.Bytes()) + var data state.Account + rlp.DecodeBytes(enc, &data) + fmt.Println(time.Now().Format(time.RFC3339), "Start clean state address ", address.Hex(), " at state root ", common.Bytes2Hex(trieRoot.Root()), "state address root", data.Root.Hex()) + signerRoot, err := resolveHash(data.Root[:], lddb.LDB()) + if err != nil { + fmt.Println(time.Now().Format(time.RFC3339), "Not found clean state address ", address.Hex(), " at state root ", common.Bytes2Hex(trieRoot.Root()), "state address root", data.Root.Hex()) + continue + } + batch := new(leveldb.Batch) + list := []*StateNode{&StateNode{node: signerRoot}} + for len(list) > 0 { + newList, total := findNewNodes(list, lddb.LDB(), batch) + list = removeNodesNil(newList, total) + } + fmt.Println(time.Now().Format(time.RFC3339), "Finish clean state address ", address.Hex(), " at state root ", common.Bytes2Hex(trieRoot.Root()), "state address root", data.Root.Hex()) + err = lddb.LDB().Write(batch, nil) + if err != nil { + fmt.Println(time.Now().Format(time.RFC3339), "Write batch leveldb error", err) + os.Exit(1) + } + } + }else { + break + } + atomic.StoreInt32(&finish, 0) + } + fmt.Println(time.Now(), "compact") + lddb.LDB().CompactRange(util.Range{}) + lddb.Close() + fmt.Println(time.Now(), "end") +} + +func removeNodesNil(list [][17]*StateNode, length int) []*StateNode { + results := make([]*StateNode, length) + index := 0 + for _, nodes := range list { + for _, node := range nodes { + if node != nil { + results[index] = node + index++ + } + } + } + return results +} +func catchEventInterupt(db *leveldb.DB) { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + go func() { + for sig := range c { + fmt.Println("catch event interrupt ", sig, running, finish) + running = false + if atomic.LoadInt32(&finish) == 0 { + close(stateRoots) + fmt.Println(time.Now(), "interrupt compact") + db.CompactRange(util.Range{}) + db.Close() + fmt.Println(time.Now(), "interrupt end") + os.Exit(1) + } + } + }() +} +func resolveHash(n trie.HashNode, db *leveldb.DB) (trie.Node, error) { + if cache.Contains(common.BytesToHash(n)) { + return nil, &trie.MissingNodeError{} + } + enc, err := db.Get(n, nil) + if err != nil || enc == nil { + return nil, &trie.MissingNodeError{} + } + return trie.MustDecodeNode(n, enc, 0), nil +} + +func getAllChilds(n StateNode, db *leveldb.DB) ([17]*StateNode, error) { + childs := [17]*StateNode{} + switch node := n.node.(type) { + case *trie.FullNode: + // Full Node, move to the first non-nil child. + for i := 0; i < len(node.Children); i++ { + child := node.Children[i] + if child != nil { + childNode := child + var err error = nil + if _, ok := child.(trie.HashNode); ok { + childNode, err = resolveHash(child.(trie.HashNode), db) + } + if err == nil { + childs[i] = &StateNode{node: childNode, path: append(n.path, byte(i))} + } else if err != nil { + _, ok := err.(*trie.MissingNodeError); + if !ok { + return childs, err + } + } + } + } + case *trie.ShortNode: + // Short Node, return the pointer singleton child + childNode := node.Val + var err error = nil + if _, ok := node.Val.(trie.HashNode); ok { + childNode, err = resolveHash(node.Val.(trie.HashNode), db) + } + if err == nil { + childs[0] = &StateNode{node: childNode, path: append(n.path, node.Key...)} + } else if err != nil { + _, ok := err.(*trie.MissingNodeError); + if !ok { + return childs, err + } + } + } + return childs, nil +} +func processNodes(node StateNode, db *leveldb.DB) ([17]*StateNode, [17]*[]byte, int) { + hash, _ := node.node.Cache() + commonHash := common.BytesToHash(hash) + newNodes := [17]*StateNode{} + keys := [17]*[]byte{} + number := 0 + if !cache.Contains(commonHash) { + childNodes, err := getAllChilds(node, db) + if err != nil { + fmt.Println("Error when get all childs node : ", common.Bytes2Hex(node.path), err) + os.Exit(1) + } + for i, child := range childNodes { + if child != nil { + if _, ok := child.node.(trie.ValueNode); ok { + buf := append(sercureKey, child.path...) + keys[i] = &buf + } else { + hash, _ := child.node.Cache() + var bytes []byte = hash + keys[i] = &bytes + newNodes[i] = child + number++ + } + } + } + cache.Add(commonHash, true) + } + return newNodes, keys, number +} + +func findNewNodes(nodes []*StateNode, db *leveldb.DB, batchlvdb *leveldb.Batch) ([][17]*StateNode, int) { + length := len(nodes) + chunkSize := length / nWorker + if len(nodes)%nWorker != 0 { + chunkSize++ + } + childNodes := make([][17]*StateNode, length) + results := make(chan ResultProcessNode) + wg := sync.WaitGroup{} + wgResults := sync.WaitGroup{} + wg.Add(nWorker) + for i := 0; i < nWorker; i++ { + from := i * chunkSize + to := from + chunkSize + if to > length { + to = length + } + go func(from int, to int) { + for j := from; j < to; j++ { + childs, keys, number := processNodes(*nodes[j], db) + wgResults.Add(1) + go func(result ResultProcessNode) { + results <- result + }(ResultProcessNode{j, number, childs, keys}) + } + wg.Done() + }(from, to) + } + wg.Wait() + total := 0 + go func() { + for result := range results { + childNodes[result.index] = result.newNodes + total = total + result.number + for _, key := range result.keys { + if key != nil { + batchlvdb.Delete(*key) + } + } + wgResults.Done() + } + }() + wgResults.Wait() + close(results) + return childNodes, total +} diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index cdebc9a99f..1b08145659 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -747,9 +747,9 @@ func setIPC(ctx *cli.Context, cfg *node.Config) { } } -// makeDatabaseHandles raises out the number of allowed file handles per process +// MakeDatabaseHandles raises out the number of allowed file handles per process // for tomo and returns half of the allowance to assign to the database. -func makeDatabaseHandles() int { +func MakeDatabaseHandles() int { limit, err := fdlimit.Current() if err != nil { Fatalf("Failed to retrieve file descriptor allowance: %v", err) @@ -1066,7 +1066,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) { cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 } - cfg.DatabaseHandles = makeDatabaseHandles() + cfg.DatabaseHandles = MakeDatabaseHandles() if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) @@ -1212,7 +1212,7 @@ func SetupNetwork(ctx *cli.Context) { func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { var ( cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 - handles = makeDatabaseHandles() + handles = MakeDatabaseHandles() ) name := "chaindata" if ctx.GlobalBool(LightModeFlag.Name) { diff --git a/trie/hasher.go b/trie/hasher.go index 2fc44787ac..cc0f006441 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -53,9 +53,9 @@ func returnHasherToPool(h *hasher) { // hash collapses a node down into a hash node, also returning a copy of the // original node initialized with the computed hash to replace the original one. -func (h *hasher) hash(n node, db *Database, force bool) (node, node, error) { +func (h *hasher) hash(n Node, db *Database, force bool) (Node, Node, error) { // If we're not storing the node, just hashing, use available cached data - if hash, dirty := n.cache(); hash != nil { + if hash, dirty := n.Cache(); hash != nil { if db == nil { return hash, n, nil } @@ -72,23 +72,23 @@ func (h *hasher) hash(n node, db *Database, force bool) (node, node, error) { // Trie not processed yet or needs storage, walk the children collapsed, cached, err := h.hashChildren(n, db) if err != nil { - return hashNode{}, n, err + return HashNode{}, n, err } hashed, err := h.store(collapsed, db, force) if err != nil { - return hashNode{}, n, err + return HashNode{}, n, err } // Cache the hash of the node for later reuse and remove // the dirty flag in commit mode. It's fine to assign these values directly // without copying the node first because hashChildren copies it. - cachedHash, _ := hashed.(hashNode) + cachedHash, _ := hashed.(HashNode) switch cn := cached.(type) { - case *shortNode: + case *ShortNode: cn.flags.hash = cachedHash if db != nil { cn.flags.dirty = false } - case *fullNode: + case *FullNode: cn.flags.hash = cachedHash if db != nil { cn.flags.dirty = false @@ -100,28 +100,28 @@ func (h *hasher) hash(n node, db *Database, force bool) (node, node, error) { // hashChildren replaces the children of a node with their hashes if the encoded // size of the child is larger than a hash, returning the collapsed node as well // as a replacement for the original node with the child hashes cached in. -func (h *hasher) hashChildren(original node, db *Database) (node, node, error) { +func (h *hasher) hashChildren(original Node, db *Database) (Node, Node, error) { var err error switch n := original.(type) { - case *shortNode: - // Hash the short node's child, caching the newly hashed subtree + case *ShortNode: + // Hash the short Node's child, caching the newly hashed subtree collapsed, cached := n.copy(), n.copy() collapsed.Key = hexToCompact(n.Key) cached.Key = common.CopyBytes(n.Key) - if _, ok := n.Val.(valueNode); !ok { + if _, ok := n.Val.(ValueNode); !ok { collapsed.Val, cached.Val, err = h.hash(n.Val, db, false) if err != nil { return original, original, err } } if collapsed.Val == nil { - collapsed.Val = valueNode(nil) // Ensure that nil children are encoded as empty strings. + collapsed.Val = ValueNode(nil) // Ensure that nil children are encoded as empty strings. } return collapsed, cached, nil - case *fullNode: + case *FullNode: // Hash the full node's children, caching the newly hashed subtrees collapsed, cached := n.copy(), n.copy() @@ -132,12 +132,12 @@ func (h *hasher) hashChildren(original node, db *Database) (node, node, error) { return original, original, err } } else { - collapsed.Children[i] = valueNode(nil) // Ensure that nil children are encoded as empty strings. + collapsed.Children[i] = ValueNode(nil) // Ensure that nil children are encoded as empty strings. } } cached.Children[16] = n.Children[16] if collapsed.Children[16] == nil { - collapsed.Children[16] = valueNode(nil) + collapsed.Children[16] = ValueNode(nil) } return collapsed, cached, nil @@ -150,9 +150,9 @@ func (h *hasher) hashChildren(original node, db *Database) (node, node, error) { // store hashes the node n and if we have a storage layer specified, it writes // the key/value pair to it and tracks any node->child references as well as any // node->external trie references. -func (h *hasher) store(n node, db *Database, force bool) (node, error) { +func (h *hasher) store(n Node, db *Database, force bool) (Node, error) { // Don't store hashes or empty nodes. - if _, isHash := n.(hashNode); n == nil || isHash { + if _, isHash := n.(HashNode); n == nil || isHash { return n, nil } // Generate the RLP encoding of the node @@ -164,11 +164,11 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) { return n, nil // Nodes smaller than 32 bytes are stored inside their parent } // Larger nodes are replaced by their hash and stored in the database. - hash, _ := n.cache() + hash, _ := n.Cache() if hash == nil { h.sha.Reset() h.sha.Write(h.tmp.Bytes()) - hash = hashNode(h.sha.Sum(nil)) + hash = HashNode(h.sha.Sum(nil)) } if db != nil { // We are pooling the trie nodes into an intermediate memory cache @@ -179,13 +179,13 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) { // Track all direct parent->child node references switch n := n.(type) { - case *shortNode: - if child, ok := n.Val.(hashNode); ok { + case *ShortNode: + if child, ok := n.Val.(HashNode); ok { db.reference(common.BytesToHash(child), hash) } - case *fullNode: + case *FullNode: for i := 0; i < 16; i++ { - if child, ok := n.Children[i].(hashNode); ok { + if child, ok := n.Children[i].(HashNode); ok { db.reference(common.BytesToHash(child), hash) } } @@ -195,13 +195,13 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) { // Track external references from account->storage trie if h.onleaf != nil { switch n := n.(type) { - case *shortNode: - if child, ok := n.Val.(valueNode); ok { + case *ShortNode: + if child, ok := n.Val.(ValueNode); ok { h.onleaf(child, hash) } - case *fullNode: + case *FullNode: for i := 0; i < 16; i++ { - if child, ok := n.Children[i].(valueNode); ok { + if child, ok := n.Children[i].(ValueNode); ok { h.onleaf(child, hash) } } diff --git a/trie/iterator.go b/trie/iterator.go index 76146c0d64..e30504b151 100644 --- a/trie/iterator.go +++ b/trie/iterator.go @@ -20,7 +20,6 @@ import ( "bytes" "container/heap" "errors" - "github.com/ethereum/go-ethereum/common" ) @@ -60,6 +59,7 @@ type NodeIterator interface { // Next moves the iterator to the next node. If the parameter is false, any child // nodes will be skipped. Next(bool) bool + // Error returns the error status of the iterator. Error() error @@ -86,7 +86,7 @@ type NodeIterator interface { // trie, which can be resumed at a later invocation. type nodeIteratorState struct { hash common.Hash // Hash of the node being iterated (nil if not standalone) - node node // Trie node being iterated + node Node // Trie node being iterated parent common.Hash // Hash of the first full ancestor node (nil if current is the root) index int // Child to be processed next pathlen int // Length of the path to this node @@ -112,7 +112,7 @@ func (e seekError) Error() string { return "seek error: " + e.err.Error() } -func newNodeIterator(trie *Trie, start []byte) NodeIterator { +func NewNodeIterator(trie *Trie, start []byte) NodeIterator { if trie.Hash() == emptyState { return new(nodeIterator) } @@ -141,7 +141,7 @@ func (it *nodeIterator) Leaf() bool { func (it *nodeIterator) LeafBlob() []byte { if len(it.stack) > 0 { - if node, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { + if node, ok := it.stack[len(it.stack)-1].node.(ValueNode); ok { return []byte(node) } } @@ -150,7 +150,7 @@ func (it *nodeIterator) LeafBlob() []byte { func (it *nodeIterator) LeafKey() []byte { if len(it.stack) > 0 { - if _, ok := it.stack[len(it.stack)-1].node.(valueNode); ok { + if _, ok := it.stack[len(it.stack)-1].node.(ValueNode); ok { return hexToKeybytes(it.path) } } @@ -250,7 +250,7 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er } func (st *nodeIteratorState) resolve(tr *Trie, path []byte) error { - if hash, ok := st.node.(hashNode); ok { + if hash, ok := st.node.(HashNode); ok { resolved, err := tr.resolveHash(hash, path) if err != nil { return err @@ -263,12 +263,12 @@ func (st *nodeIteratorState) resolve(tr *Trie, path []byte) error { func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Hash) (*nodeIteratorState, []byte, bool) { switch node := parent.node.(type) { - case *fullNode: - // Full node, move to the first non-nil child. + case *FullNode: + // Full Node, move to the first non-nil child. for i := parent.index + 1; i < len(node.Children); i++ { child := node.Children[i] if child != nil { - hash, _ := child.cache() + hash, _ := child.Cache() state := &nodeIteratorState{ hash: common.BytesToHash(hash), node: child, @@ -281,10 +281,10 @@ func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Has return state, path, true } } - case *shortNode: + case *ShortNode: // Short node, return the pointer singleton child if parent.index < 0 { - hash, _ := node.Val.cache() + hash, _ := node.Val.Cache() state := &nodeIteratorState{ hash: common.BytesToHash(hash), node: node.Val, diff --git a/trie/node.go b/trie/node.go index a7697fc0c6..4b76f2b559 100644 --- a/trie/node.go +++ b/trie/node.go @@ -27,63 +27,63 @@ import ( var indices = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "[17]"} -type node interface { +type Node interface { fstring(string) string - cache() (hashNode, bool) + Cache() (HashNode, bool) canUnload(cachegen, cachelimit uint16) bool } type ( - fullNode struct { - Children [17]node // Actual trie node data to encode/decode (needs custom encoder) + FullNode struct { + Children [17]Node // Actual trie node data to encode/decode (needs custom encoder) flags nodeFlag } - shortNode struct { + ShortNode struct { Key []byte - Val node + Val Node flags nodeFlag } - hashNode []byte - valueNode []byte + HashNode []byte + ValueNode []byte ) // EncodeRLP encodes a full node into the consensus RLP format. -func (n *fullNode) EncodeRLP(w io.Writer) error { +func (n *FullNode) EncodeRLP(w io.Writer) error { return rlp.Encode(w, n.Children) } -func (n *fullNode) copy() *fullNode { copy := *n; return © } -func (n *shortNode) copy() *shortNode { copy := *n; return © } +func (n *FullNode) copy() *FullNode { copy := *n; return © } +func (n *ShortNode) copy() *ShortNode { copy := *n; return © } // nodeFlag contains caching-related metadata about a node. type nodeFlag struct { - hash hashNode // cached hash of the node (may be nil) + hash HashNode // cached hash of the node (may be nil) gen uint16 // cache generation counter dirty bool // whether the node has changes that must be written to the database } -// canUnload tells whether a node can be unloaded. +// canUnload tells whether a Node can be unloaded. func (n *nodeFlag) canUnload(cachegen, cachelimit uint16) bool { return !n.dirty && cachegen-n.gen >= cachelimit } -func (n *fullNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) } -func (n *shortNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) } -func (n hashNode) canUnload(uint16, uint16) bool { return false } -func (n valueNode) canUnload(uint16, uint16) bool { return false } +func (n *FullNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) } +func (n *ShortNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) } +func (n HashNode) canUnload(uint16, uint16) bool { return false } +func (n ValueNode) canUnload(uint16, uint16) bool { return false } -func (n *fullNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty } -func (n *shortNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty } -func (n hashNode) cache() (hashNode, bool) { return nil, true } -func (n valueNode) cache() (hashNode, bool) { return nil, true } +func (n *FullNode) Cache() (HashNode, bool) { return n.flags.hash, n.flags.dirty } +func (n *ShortNode) Cache() (HashNode, bool) { return n.flags.hash, n.flags.dirty } +func (n HashNode) Cache() (HashNode, bool) { return nil, true } +func (n ValueNode) Cache() (HashNode, bool) { return nil, true } // Pretty printing. -func (n *fullNode) String() string { return n.fstring("") } -func (n *shortNode) String() string { return n.fstring("") } -func (n hashNode) String() string { return n.fstring("") } -func (n valueNode) String() string { return n.fstring("") } +func (n *FullNode) String() string { return n.fstring("") } +func (n *ShortNode) String() string { return n.fstring("") } +func (n HashNode) String() string { return n.fstring("") } +func (n ValueNode) String() string { return n.fstring("") } -func (n *fullNode) fstring(ind string) string { +func (n *FullNode) fstring(ind string) string { resp := fmt.Sprintf("[\n%s ", ind) for i, node := range n.Children { if node == nil { @@ -94,17 +94,17 @@ func (n *fullNode) fstring(ind string) string { } return resp + fmt.Sprintf("\n%s] ", ind) } -func (n *shortNode) fstring(ind string) string { +func (n *ShortNode) fstring(ind string) string { return fmt.Sprintf("{%x: %v} ", n.Key, n.Val.fstring(ind+" ")) } -func (n hashNode) fstring(ind string) string { +func (n HashNode) fstring(ind string) string { return fmt.Sprintf("<%x> ", []byte(n)) } -func (n valueNode) fstring(ind string) string { +func (n ValueNode) fstring(ind string) string { return fmt.Sprintf("%x ", []byte(n)) } -func mustDecodeNode(hash, buf []byte, cachegen uint16) node { +func MustDecodeNode(hash, buf []byte, cachegen uint16) Node { n, err := decodeNode(hash, buf, cachegen) if err != nil { panic(fmt.Sprintf("node %x: %v", hash, err)) @@ -113,7 +113,7 @@ func mustDecodeNode(hash, buf []byte, cachegen uint16) node { } // decodeNode parses the RLP encoding of a trie node. -func decodeNode(hash, buf []byte, cachegen uint16) (node, error) { +func decodeNode(hash, buf []byte, cachegen uint16) (Node, error) { if len(buf) == 0 { return nil, io.ErrUnexpectedEOF } @@ -133,7 +133,7 @@ func decodeNode(hash, buf []byte, cachegen uint16) (node, error) { } } -func decodeShort(hash, buf, elems []byte, cachegen uint16) (node, error) { +func decodeShort(hash, buf, elems []byte, cachegen uint16) (Node, error) { kbuf, rest, err := rlp.SplitString(elems) if err != nil { return nil, err @@ -146,17 +146,17 @@ func decodeShort(hash, buf, elems []byte, cachegen uint16) (node, error) { if err != nil { return nil, fmt.Errorf("invalid value node: %v", err) } - return &shortNode{key, append(valueNode{}, val...), flag}, nil + return &ShortNode{key, append(ValueNode{}, val...), flag}, nil } r, _, err := decodeRef(rest, cachegen) if err != nil { return nil, wrapError(err, "val") } - return &shortNode{key, r, flag}, nil + return &ShortNode{key, r, flag}, nil } -func decodeFull(hash, buf, elems []byte, cachegen uint16) (*fullNode, error) { - n := &fullNode{flags: nodeFlag{hash: hash, gen: cachegen}} +func decodeFull(hash, buf, elems []byte, cachegen uint16) (*FullNode, error) { + n := &FullNode{flags: nodeFlag{hash: hash, gen: cachegen}} for i := 0; i < 16; i++ { cld, rest, err := decodeRef(elems, cachegen) if err != nil { @@ -169,14 +169,14 @@ func decodeFull(hash, buf, elems []byte, cachegen uint16) (*fullNode, error) { return n, err } if len(val) > 0 { - n.Children[16] = append(valueNode{}, val...) + n.Children[16] = append(ValueNode{}, val...) } return n, nil } const hashLen = len(common.Hash{}) -func decodeRef(buf []byte, cachegen uint16) (node, []byte, error) { +func decodeRef(buf []byte, cachegen uint16) (Node, []byte, error) { kind, val, rest, err := rlp.Split(buf) if err != nil { return nil, buf, err @@ -195,7 +195,7 @@ func decodeRef(buf []byte, cachegen uint16) (node, []byte, error) { // empty node return nil, rest, nil case kind == rlp.String && len(val) == 32: - return append(hashNode{}, val...), rest, nil + return append(HashNode{}, val...), rest, nil default: return nil, nil, fmt.Errorf("invalid RLP string size %d (want 0 or 32)", len(val)) } diff --git a/trie/proof.go b/trie/proof.go index 508e4a6cf4..32738bd867 100644 --- a/trie/proof.go +++ b/trie/proof.go @@ -37,11 +37,11 @@ import ( func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error { // Collect all nodes on the path to key. key = keybytesToHex(key) - nodes := []node{} + nodes := []Node{} tn := t.root for len(key) > 0 && tn != nil { switch n := tn.(type) { - case *shortNode: + case *ShortNode: if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { // The trie doesn't contain the key. tn = nil @@ -50,11 +50,11 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error { key = key[len(n.Key):] } nodes = append(nodes, n) - case *fullNode: + case *FullNode: tn = n.Children[key[0]] key = key[1:] nodes = append(nodes, n) - case hashNode: + case HashNode: var err error tn, err = t.resolveHash(n, nil) if err != nil { @@ -71,7 +71,7 @@ func (t *Trie) Prove(key []byte, fromLevel uint, proofDb ethdb.Putter) error { // if encoding doesn't work and we're not writing to any database. n, _, _ = hasher.hashChildren(n, nil) hn, _ := hasher.store(n, nil, false) - if hash, ok := hn.(hashNode); ok || i == 0 { + if hash, ok := hn.(HashNode); ok || i == 0 { // If the node's database encoding is a hash (or is the // root node), it becomes a proof element. if fromLevel > 0 { @@ -119,32 +119,32 @@ func VerifyProof(rootHash common.Hash, key []byte, proofDb DatabaseReader) (valu case nil: // The trie doesn't contain the key. return nil, nil, i - case hashNode: + case HashNode: key = keyrest copy(wantHash[:], cld) - case valueNode: + case ValueNode: return cld, nil, i + 1 } } } -func get(tn node, key []byte) ([]byte, node) { +func get(tn Node, key []byte) ([]byte, Node) { for { switch n := tn.(type) { - case *shortNode: + case *ShortNode: if len(key) < len(n.Key) || !bytes.Equal(n.Key, key[:len(n.Key)]) { return nil, nil } tn = n.Val key = key[len(n.Key):] - case *fullNode: + case *FullNode: tn = n.Children[key[0]] key = key[1:] - case hashNode: + case HashNode: return key, n case nil: return key, nil - case valueNode: + case ValueNode: return nil, n default: panic(fmt.Sprintf("%T: invalid node: %v", tn, tn)) diff --git a/trie/sync.go b/trie/sync.go index b573a9f732..3e0939fddd 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -248,21 +248,21 @@ func (s *TrieSync) schedule(req *request) { // children retrieves all the missing children of a state trie entry for future // retrieval scheduling. -func (s *TrieSync) children(req *request, object node) ([]*request, error) { +func (s *TrieSync) children(req *request, object Node) ([]*request, error) { // Gather all the children of the node, irrelevant whether known or not type child struct { - node node + node Node depth int } children := []child{} switch node := (object).(type) { - case *shortNode: + case *ShortNode: children = []child{{ node: node.Val, depth: req.depth + len(node.Key), }} - case *fullNode: + case *FullNode: for i := 0; i < 17; i++ { if node.Children[i] != nil { children = append(children, child{ @@ -279,14 +279,14 @@ func (s *TrieSync) children(req *request, object node) ([]*request, error) { for _, child := range children { // Notify any external watcher of a new key/value node if req.callback != nil { - if node, ok := (child.node).(valueNode); ok { + if node, ok := (child.node).(ValueNode); ok { if err := req.callback(node, req.hash); err != nil { return nil, err } } } // If the child references another node, resolve or schedule - if node, ok := (child.node).(hashNode); ok { + if node, ok := (child.node).(HashNode); ok { // Try to resolve the node from the local database hash := common.BytesToHash(node) if _, ok := s.membatch.batch[hash]; ok { diff --git a/trie/trie.go b/trie/trie.go index 31a404e3a0..0f0688a03e 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -66,7 +66,7 @@ type LeafCallback func(leaf []byte, parent common.Hash) error // Trie is not safe for concurrent use. type Trie struct { db *Database - root node + root Node originalRoot common.Hash // Cache generation values. @@ -114,7 +114,7 @@ func New(root common.Hash, db *Database) (*Trie, error) { // NodeIterator returns an iterator that returns nodes of the trie. Iteration starts at // the key after the given start key. func (t *Trie) NodeIterator(start []byte) NodeIterator { - return newNodeIterator(t, start) + return NewNodeIterator(t, start) } // Get returns the value for key stored in the trie. @@ -139,13 +139,13 @@ func (t *Trie) TryGet(key []byte) ([]byte, error) { return value, err } -func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode node, didResolve bool, err error) { +func (t *Trie) tryGet(origNode Node, key []byte, pos int) (value []byte, newnode Node, didResolve bool, err error) { switch n := (origNode).(type) { case nil: return nil, nil, false, nil - case valueNode: + case ValueNode: return n, n, false, nil - case *shortNode: + case *ShortNode: if len(key)-pos < len(n.Key) || !bytes.Equal(n.Key, key[pos:pos+len(n.Key)]) { // key not found in trie return nil, n, false, nil @@ -157,7 +157,7 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode n.flags.gen = t.cachegen } return value, n, didResolve, err - case *fullNode: + case *FullNode: value, newnode, didResolve, err = t.tryGet(n.Children[key[pos]], key, pos+1) if err == nil && didResolve { n = n.copy() @@ -165,7 +165,7 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode n.Children[key[pos]] = newnode } return value, n, didResolve, err - case hashNode: + case HashNode: child, err := t.resolveHash(n, key[:pos]) if err != nil { return nil, n, true, err @@ -200,7 +200,7 @@ func (t *Trie) Update(key, value []byte) { func (t *Trie) TryUpdate(key, value []byte) error { k := keybytesToHex(key) if len(value) != 0 { - _, n, err := t.insert(t.root, nil, k, valueNode(value)) + _, n, err := t.insert(t.root, nil, k, ValueNode(value)) if err != nil { return err } @@ -215,15 +215,15 @@ func (t *Trie) TryUpdate(key, value []byte) error { return nil } -func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error) { +func (t *Trie) insert(n Node, prefix, key []byte, value Node) (bool, Node, error) { if len(key) == 0 { - if v, ok := n.(valueNode); ok { - return !bytes.Equal(v, value.(valueNode)), value, nil + if v, ok := n.(ValueNode); ok { + return !bytes.Equal(v, value.(ValueNode)), value, nil } return true, value, nil } switch n := n.(type) { - case *shortNode: + case *ShortNode: matchlen := prefixLen(key, n.Key) // If the whole key matches, keep this short node as is // and only update the value. @@ -232,10 +232,10 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error if !dirty || err != nil { return false, n, err } - return true, &shortNode{n.Key, nn, t.newFlag()}, nil + return true, &ShortNode{n.Key, nn, t.newFlag()}, nil } // Otherwise branch out at the index where they differ. - branch := &fullNode{flags: t.newFlag()} + branch := &FullNode{flags: t.newFlag()} var err error _, branch.Children[n.Key[matchlen]], err = t.insert(nil, append(prefix, n.Key[:matchlen+1]...), n.Key[matchlen+1:], n.Val) if err != nil { @@ -250,9 +250,9 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error return true, branch, nil } // Otherwise, replace it with a short node leading up to the branch. - return true, &shortNode{key[:matchlen], branch, t.newFlag()}, nil + return true, &ShortNode{key[:matchlen], branch, t.newFlag()}, nil - case *fullNode: + case *FullNode: dirty, nn, err := t.insert(n.Children[key[0]], append(prefix, key[0]), key[1:], value) if !dirty || err != nil { return false, n, err @@ -263,9 +263,9 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error return true, n, nil case nil: - return true, &shortNode{key, value, t.newFlag()}, nil + return true, &ShortNode{key, value, t.newFlag()}, nil - case hashNode: + case HashNode: // We've hit a part of the trie that isn't loaded yet. Load // the node and insert into it. This leaves all child nodes on // the path to the value in the trie. @@ -306,9 +306,9 @@ func (t *Trie) TryDelete(key []byte) error { // delete returns the new root of the trie with key deleted. // It reduces the trie to minimal form by simplifying // nodes on the way up after deleting recursively. -func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { +func (t *Trie) delete(n Node, prefix, key []byte) (bool, Node, error) { switch n := n.(type) { - case *shortNode: + case *ShortNode: matchlen := prefixLen(key, n.Key) if matchlen < len(n.Key) { return false, n, nil // don't replace n on mismatch @@ -325,19 +325,19 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { return false, n, err } switch child := child.(type) { - case *shortNode: + case *ShortNode: // Deleting from the subtrie reduced it to another // short node. Merge the nodes to avoid creating a // shortNode{..., shortNode{...}}. Use concat (which // always creates a new slice) instead of append to // avoid modifying n.Key since it might be shared with // other nodes. - return true, &shortNode{concat(n.Key, child.Key...), child.Val, t.newFlag()}, nil + return true, &ShortNode{concat(n.Key, child.Key...), child.Val, t.newFlag()}, nil default: - return true, &shortNode{n.Key, child, t.newFlag()}, nil + return true, &ShortNode{n.Key, child, t.newFlag()}, nil } - case *fullNode: + case *FullNode: dirty, nn, err := t.delete(n.Children[key[0]], append(prefix, key[0]), key[1:]) if !dirty || err != nil { return false, n, err @@ -368,7 +368,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { } if pos >= 0 { if pos != 16 { - // If the remaining entry is a short node, it replaces + // If the remaining entry is a short node, it replaces // n and its key gets the missing nibble tacked to the // front. This avoids creating an invalid // shortNode{..., shortNode{...}}. Since the entry @@ -378,25 +378,25 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) { if err != nil { return false, nil, err } - if cnode, ok := cnode.(*shortNode); ok { + if cnode, ok := cnode.(*ShortNode); ok { k := append([]byte{byte(pos)}, cnode.Key...) - return true, &shortNode{k, cnode.Val, t.newFlag()}, nil + return true, &ShortNode{k, cnode.Val, t.newFlag()}, nil } } // Otherwise, n is replaced by a one-nibble short node // containing the child. - return true, &shortNode{[]byte{byte(pos)}, n.Children[pos], t.newFlag()}, nil + return true, &ShortNode{[]byte{byte(pos)}, n.Children[pos], t.newFlag()}, nil } // n still contains at least two values and cannot be reduced. return true, n, nil - case valueNode: + case ValueNode: return true, nil, nil case nil: return false, nil, nil - case hashNode: + case HashNode: // We've hit a part of the trie that isn't loaded yet. Load // the node and delete from it. This leaves all child nodes on // the path to the value in the trie. @@ -422,14 +422,14 @@ func concat(s1 []byte, s2 ...byte) []byte { return r } -func (t *Trie) resolve(n node, prefix []byte) (node, error) { - if n, ok := n.(hashNode); ok { +func (t *Trie) resolve(n Node, prefix []byte) (Node, error) { + if n, ok := n.(HashNode); ok { return t.resolveHash(n, prefix) } return n, nil } -func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) { +func (t *Trie) resolveHash(n HashNode, prefix []byte) (Node, error) { cacheMissCounter.Inc(1) hash := common.BytesToHash(n) @@ -438,7 +438,7 @@ func (t *Trie) resolveHash(n hashNode, prefix []byte) (node, error) { if err != nil || enc == nil { return nil, &MissingNodeError{NodeHash: hash, Path: prefix} } - return mustDecodeNode(n, enc, t.cachegen), nil + return MustDecodeNode(n, enc, t.cachegen), nil } // Root returns the root hash of the trie. @@ -450,7 +450,7 @@ func (t *Trie) Root() []byte { return t.Hash().Bytes() } func (t *Trie) Hash() common.Hash { hash, cached, _ := t.hashRoot(nil, nil) t.root = cached - return common.BytesToHash(hash.(hashNode)) + return common.BytesToHash(hash.(HashNode)) } // Commit writes all nodes to the trie's memory database, tracking the internal @@ -465,12 +465,12 @@ func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) { } t.root = cached t.cachegen++ - return common.BytesToHash(hash.(hashNode)), nil + return common.BytesToHash(hash.(HashNode)), nil } -func (t *Trie) hashRoot(db *Database, onleaf LeafCallback) (node, node, error) { +func (t *Trie) hashRoot(db *Database, onleaf LeafCallback) (Node, Node, error) { if t.root == nil { - return hashNode(emptyRoot.Bytes()), nil, nil + return HashNode(emptyRoot.Bytes()), nil, nil } h := newHasher(t.cachegen, t.cachelimit, onleaf) defer returnHasherToPool(h) diff --git a/trie/trie_test.go b/trie/trie_test.go index 9972226288..8a8436270a 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -469,14 +469,14 @@ func runRandTest(rt randTest) bool { return true } -func checkCacheInvariant(n, parent node, parentCachegen uint16, parentDirty bool, depth int) error { - var children []node +func checkCacheInvariant(n, parent Node, parentCachegen uint16, parentDirty bool, depth int) error { + var children []Node var flag nodeFlag switch n := n.(type) { - case *shortNode: + case *ShortNode: flag = n.flags - children = []node{n.Val} - case *fullNode: + children = []Node{n.Val} + case *FullNode: flag = n.flags children = n.Children[:] default: From ba554511429b54b287a17e90bb98c18d02edfee6 Mon Sep 17 00:00:00 2001 From: Nguyen Ba Tam Date: Fri, 22 Feb 2019 17:05:03 +0700 Subject: [PATCH 6/6] create new func penalties for hard fork --- cmd/tomoclean/main.go | 43 ++++---- common/constants.go | 5 +- consensus/posv/posv.go | 31 +++--- contracts/utils.go | 62 +----------- core/blockchain.go | 6 +- core/state_processor.go | 6 +- core/tx_pool.go | 8 +- eth/backend.go | 211 ++++++++++++++++++++++------------------ internal/ethapi/api.go | 4 +- miner/worker.go | 4 +- params/config.go | 4 +- trie/node.go | 2 +- 12 files changed, 173 insertions(+), 213 deletions(-) diff --git a/cmd/tomoclean/main.go b/cmd/tomoclean/main.go index 991339ee66..bd41f9234c 100644 --- a/cmd/tomoclean/main.go +++ b/cmd/tomoclean/main.go @@ -25,9 +25,12 @@ import ( var ( dir = flag.String("dir", "", "dir to mainet chain data") cacheSize = flag.Int("size", 1000000, "dir to mainet chain data") - file = flag.String("file", "", "dir to mainet chain data") ) +type TrieRoot struct { + trie *trie.SecureTrie + number uint64 +} type StateNode struct { node trie.Node path []byte @@ -45,7 +48,7 @@ var cleanAddress = []common.Address{common.HexToAddress(common.BlockSigners)} var cache *lru.Cache var finish = int32(0) var running = true -var stateRoots = make(chan *trie.SecureTrie) +var stateRoots = make(chan TrieRoot) func main() { flag.Parse() @@ -63,10 +66,9 @@ func main() { if err != nil { continue } - fmt.Println(time.Now().Format(time.RFC3339), "Found a trie state root at block ", i, "state root ", root.Hex()) if running { - stateRoots <- trieRoot - }else { + stateRoots <- TrieRoot{trieRoot, i} + } else { break } } @@ -78,29 +80,31 @@ func main() { atomic.StoreInt32(&finish, 1) if running { for _, address := range cleanAddress { - enc := trieRoot.Get(address.Bytes()) + enc := trieRoot.trie.Get(address.Bytes()) var data state.Account rlp.DecodeBytes(enc, &data) - fmt.Println(time.Now().Format(time.RFC3339), "Start clean state address ", address.Hex(), " at state root ", common.Bytes2Hex(trieRoot.Root()), "state address root", data.Root.Hex()) + fmt.Println(time.Now().Format(time.RFC3339), "Start clean state address ", address.Hex(), " at block ", trieRoot.number) signerRoot, err := resolveHash(data.Root[:], lddb.LDB()) if err != nil { - fmt.Println(time.Now().Format(time.RFC3339), "Not found clean state address ", address.Hex(), " at state root ", common.Bytes2Hex(trieRoot.Root()), "state address root", data.Root.Hex()) + fmt.Println(time.Now().Format(time.RFC3339), "Not found clean state address ", address.Hex(), " at block ", trieRoot.number) continue } batch := new(leveldb.Batch) - list := []*StateNode{&StateNode{node: signerRoot}} + count := 1 + list := []*StateNode{{node: signerRoot}} for len(list) > 0 { newList, total := findNewNodes(list, lddb.LDB(), batch) + count = count + 17*len(newList) list = removeNodesNil(newList, total) } - fmt.Println(time.Now().Format(time.RFC3339), "Finish clean state address ", address.Hex(), " at state root ", common.Bytes2Hex(trieRoot.Root()), "state address root", data.Root.Hex()) + fmt.Println(time.Now().Format(time.RFC3339), "Finish clean state address ", address.Hex(), " at block ", trieRoot.number, " keys ", count) err = lddb.LDB().Write(batch, nil) if err != nil { fmt.Println(time.Now().Format(time.RFC3339), "Write batch leveldb error", err) os.Exit(1) } } - }else { + } else { break } atomic.StoreInt32(&finish, 0) @@ -133,10 +137,7 @@ func catchEventInterupt(db *leveldb.DB) { running = false if atomic.LoadInt32(&finish) == 0 { close(stateRoots) - fmt.Println(time.Now(), "interrupt compact") - db.CompactRange(util.Range{}) db.Close() - fmt.Println(time.Now(), "interrupt end") os.Exit(1) } } @@ -169,7 +170,7 @@ func getAllChilds(n StateNode, db *leveldb.DB) ([17]*StateNode, error) { if err == nil { childs[i] = &StateNode{node: childNode, path: append(n.path, byte(i))} } else if err != nil { - _, ok := err.(*trie.MissingNodeError); + _, ok := err.(*trie.MissingNodeError) if !ok { return childs, err } @@ -186,7 +187,7 @@ func getAllChilds(n StateNode, db *leveldb.DB) ([17]*StateNode, error) { if err == nil { childs[0] = &StateNode{node: childNode, path: append(n.path, node.Key...)} } else if err != nil { - _, ok := err.(*trie.MissingNodeError); + _, ok := err.(*trie.MissingNodeError) if !ok { return childs, err } @@ -234,8 +235,7 @@ func findNewNodes(nodes []*StateNode, db *leveldb.DB, batchlvdb *leveldb.Batch) childNodes := make([][17]*StateNode, length) results := make(chan ResultProcessNode) wg := sync.WaitGroup{} - wgResults := sync.WaitGroup{} - wg.Add(nWorker) + wg.Add(length) for i := 0; i < nWorker; i++ { from := i * chunkSize to := from + chunkSize @@ -245,15 +245,12 @@ func findNewNodes(nodes []*StateNode, db *leveldb.DB, batchlvdb *leveldb.Batch) go func(from int, to int) { for j := from; j < to; j++ { childs, keys, number := processNodes(*nodes[j], db) - wgResults.Add(1) go func(result ResultProcessNode) { results <- result }(ResultProcessNode{j, number, childs, keys}) } - wg.Done() }(from, to) } - wg.Wait() total := 0 go func() { for result := range results { @@ -264,10 +261,10 @@ func findNewNodes(nodes []*StateNode, db *leveldb.DB, batchlvdb *leveldb.Batch) batchlvdb.Delete(*key) } } - wgResults.Done() + wg.Done() } }() - wgResults.Wait() + wg.Wait() close(results) return childNodes, total } diff --git a/common/constants.go b/common/constants.go index 701a252eb9..7c66a44368 100644 --- a/common/constants.go +++ b/common/constants.go @@ -18,11 +18,12 @@ const ( LimitThresholdNonceInQueue = 10 DefaultMinGasPrice = 2500 MergeSignRange = 15 - RangeReturnSigner = 90 + RangeReturnSigner = 150 + MinimunMinerBlockPerEpoch = 1 ) var TIP2019Block = big.NewInt(1050000) -var TIPEVMSignerBlock = big.NewInt(2500000) +var TIPSigning = big.NewInt(3000000) var IsTestnet bool = false var StoreRewardFolder string var RollbackHash Hash diff --git a/consensus/posv/posv.go b/consensus/posv/posv.go index 3ccdb81419..f11e8b3455 100644 --- a/consensus/posv/posv.go +++ b/consensus/posv/posv.go @@ -227,10 +227,10 @@ type Posv struct { BlockSigners *lru.Cache HookReward func(chain consensus.ChainReader, state *state.StateDB, header *types.Header) (error, map[string]interface{}) - HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) - HookPenaltyTIPEVM func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) - HookValidator func(header *types.Header, signers []common.Address) ([]byte, error) - HookVerifyMNs func(header *types.Header, signers []common.Address) error + HookPenalty func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) + HookPenaltyTIPSigning func(chain consensus.ChainReader, header *types.Header, candidate []common.Address) ([]common.Address, error) + HookValidator func(header *types.Header, signers []common.Address) ([]byte, error) + HookVerifyMNs func(header *types.Header, signers []common.Address) error } // New creates a PoSV proof-of-stake-voting consensus engine with the initial @@ -398,12 +398,12 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types. } // If the block is a checkpoint block, verify the signer list if number%c.config.Epoch == 0 { + signers := snap.GetSigners() penPenalties := []common.Address{} - if c.HookPenalty != nil || c.HookPenaltyTIPEVM != nil { - var penPenalties []common.Address = nil + if c.HookPenalty != nil || c.HookPenaltyTIPSigning != nil { var err error = nil - if chain.Config().IsTIPEVMSigner(header.Number) { - penPenalties, err = c.HookPenaltyTIPEVM(chain, number) + if chain.Config().IsTIPSigning(header.Number) { + penPenalties, err = c.HookPenaltyTIPSigning(chain, header, signers) } else { penPenalties, err = c.HookPenalty(chain, number) } @@ -418,7 +418,6 @@ func (c *Posv) verifyCascadingFields(chain consensus.ChainReader, header *types. return errInvalidCheckpointPenalties } } - signers := snap.GetSigners() signers = common.RemoveItemFromArray(signers, penPenalties) for i := 1; i <= common.LimitPenaltyEpoch; i++ { if number > uint64(i)*c.config.Epoch { @@ -795,11 +794,11 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error header.Extra = header.Extra[:extraVanity] masternodes := snap.GetSigners() if number >= c.config.Epoch && number%c.config.Epoch == 0 { - if c.HookPenalty != nil || c.HookPenaltyTIPEVM != nil { + if c.HookPenalty != nil || c.HookPenaltyTIPSigning != nil { var penMasternodes []common.Address = nil var err error = nil - if chain.Config().IsTIPEVMSigner(header.Number) { - penMasternodes, err = c.HookPenaltyTIPEVM(chain, number) + if chain.Config().IsTIPSigning(header.Number) { + penMasternodes, err = c.HookPenaltyTIPSigning(chain, header, masternodes) } else { penMasternodes, err = c.HookPenalty(chain, number) } @@ -810,7 +809,7 @@ func (c *Posv) Prepare(chain consensus.ChainReader, header *types.Header) error // penalize bad masternode(s) masternodes = common.RemoveItemFromArray(masternodes, penMasternodes) for _, address := range penMasternodes { - log.Debug("Penalty status", "address", address, "block number", number) + log.Debug("Penalty status", "address", address, "number", number) } header.Penalties = common.ExtractAddressToBytes(penMasternodes) } @@ -1079,15 +1078,15 @@ func (c *Posv) CacheData(header *types.Header, txs []*types.Transaction, receipt return signTxs } -func (c *Posv) CacheSigner(header *types.Header, txs []*types.Transaction) []*types.Transaction { +func (c *Posv) CacheSigner(hash common.Hash, txs []*types.Transaction) []*types.Transaction { signTxs := []*types.Transaction{} for _, tx := range txs { if tx.IsSigningTransaction() { signTxs = append(signTxs, tx) } } - log.Debug("Save tx signers to cache", "hash", header.Hash().String(), "number", header.Number, "len(txs)", len(signTxs)) - c.BlockSigners.Add(header.Hash(), signTxs) + log.Debug("Save tx signers to cache", "hash", hash.String(), "len(txs)", len(signTxs)) + c.BlockSigners.Add(hash, signTxs) return signTxs } diff --git a/contracts/utils.go b/contracts/utils.go index dfe20de790..b60a6b95de 100644 --- a/contracts/utils.go +++ b/contracts/utils.go @@ -306,62 +306,6 @@ func DecryptRandomizeFromSecretsAndOpening(secrets [][32]byte, opening [32]byte) return random, nil } -// Get txw signed for block using cache or block body inside. -func GetSignersSignedAtBlockHash(c *posv.Posv, chain consensus.ChainReader, data map[common.Hash][]common.Address, header *types.Header, curNumber uint64) map[common.Hash][]common.Address { - if signData, ok := c.BlockSigners.Get(header.Hash()); ok { - txs := signData.([]*types.Transaction) - for _, tx := range txs { - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() - data[blkHash] = append(data[blkHash], from) - } - } else { - log.Debug("Failed get from cached", "hash", header.Hash().String(), "number", curNumber) - block := chain.GetBlock(header.Hash(), curNumber) - txs := block.Transactions() - receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), curNumber) - - var signTxs []*types.Transaction - for _, tx := range txs { - if tx.IsSigningTransaction() { - var b uint - for _, r := range receipts { - if r.TxHash == tx.Hash() { - if len(r.PostState) > 0 { - b = types.ReceiptStatusSuccessful - } else { - b = r.Status - } - break - } - } - - if b == types.ReceiptStatusFailed { - continue - } - - signTxs = append(signTxs, tx) - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() - data[blkHash] = append(data[blkHash], from) - } - } - c.BlockSigners.Add(header.Hash(), signTxs) - } - - return data -} - -// Get signers list from bytes. -func GetSignersFromBytes(byteHeader []byte) []common.Address { - signers := make([]common.Address, len(byteHeader)/common.AddressLength) - for i := 0; i < len(signers); i++ { - copy(signers[i][:], byteHeader[i*common.AddressLength:]) - } - - return signers -} - // Calculate reward for reward checkpoint. func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, header *types.Header, rCheckpoint uint64, totalSigner *uint64) (map[common.Address]*rewardLog, error) { // Not reward for singer of genesis block and only calculate reward at checkpoint block. @@ -381,11 +325,11 @@ func GetRewardForCheckpoint(c *posv.Posv, chain consensus.ChainReader, header *t log.Debug("Failed get from cached", "hash", header.Hash().String(), "number", i) block := chain.GetBlock(header.Hash(), i) txs := block.Transactions() - if !chain.Config().IsTIPEVMSigner(header.Number) { + if !chain.Config().IsTIPSigning(header.Number) { receipts := core.GetBlockReceipts(c.GetDb(), header.Hash(), i) - signData = c.CacheData(header, txs, receipts); + signData = c.CacheData(header, txs, receipts) } else { - signData = c.CacheSigner(header, txs); + signData = c.CacheSigner(header.Hash(), txs) } } txs := signData.([]*types.Transaction) diff --git a/core/blockchain.go b/core/blockchain.go index ae4536bcaf..ac5518fb08 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -507,7 +507,7 @@ func (bc *BlockChain) insert(block *types.Block) { bc.currentBlock.Store(block) // save cache BlockSigners - if bc.chainConfig.Posv != nil && !bc.chainConfig.IsTIPEVMSigner(block.Number()) { + if bc.chainConfig.Posv != nil && !bc.chainConfig.IsTIPSigning(block.Number()) { engine := bc.Engine().(*posv.Posv) engine.CacheData(block.Header(), block.Transactions(), bc.GetReceiptsByHash(block.Hash())) } @@ -1020,9 +1020,9 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. bc.insert(block) } // save cache BlockSigners - if bc.chainConfig.Posv != nil && bc.chainConfig.IsTIPEVMSigner(block.Number()) { + if bc.chainConfig.Posv != nil && bc.chainConfig.IsTIPSigning(block.Number()) { engine := bc.Engine().(*posv.Posv) - engine.CacheSigner(block.Header(), block.Transactions()) + engine.CacheSigner(block.Header().Hash(), block.Transactions()) } bc.futureBlocks.Remove(block.Hash()) return status, nil diff --git a/core/state_processor.go b/core/state_processor.go index d21ecd70f4..c2df09f994 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -73,7 +73,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } - if p.config.IsTIPEVMSigner(header.Number) { + if common.TIPSigning.Cmp(header.Number) == 0 { statedb.DeleteAddress(common.HexToAddress(common.BlockSigners)) } InitSignerInTransactions(p.config, header, block.Transactions()) @@ -104,7 +104,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } - if p.config.IsTIPEVMSigner(header.Number) { + if common.TIPSigning.Cmp(header.Number) == 0 { statedb.DeleteAddress(common.HexToAddress(common.BlockSigners)) } if cBlock.stop { @@ -138,7 +138,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) { - if tx.To() != nil && tx.To().String() == common.BlockSigners && config.IsTIPEVMSigner(header.Number) { + if tx.To() != nil && tx.To().String() == common.BlockSigners && config.IsTIPSigning(header.Number) { return ApplySignTransaction(config, statedb, header, tx, usedGas) } msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) diff --git a/core/tx_pool.go b/core/tx_pool.go index c4a777a0fb..3d7be4c11d 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -218,8 +218,8 @@ type TxPool struct { wg sync.WaitGroup // for shutdown sync - homestead bool - IsMasterNode func(address common.Address) bool + homestead bool + IsSigner func(address common.Address) bool } // NewTxPool creates a new transaction pool to gather, sort and filter inbound @@ -592,7 +592,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { // Drop non-local transactions under our own minimal accepted gas price local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 { - if !tx.IsSpecialTransaction() || (pool.IsMasterNode != nil && !pool.IsMasterNode(from)) { + if !tx.IsSpecialTransaction() || (pool.IsSigner != nil && !pool.IsSigner(from)) { return ErrUnderpriced } } @@ -661,7 +661,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) { return false, err } from, _ := types.Sender(pool.signer, tx) // already validated - if tx.IsSpecialTransaction() && pool.IsMasterNode != nil && pool.IsMasterNode(from) && pool.pendingState.GetNonce(from) == tx.Nonce() { + if tx.IsSpecialTransaction() && pool.IsSigner != nil && pool.IsSigner(from) && pool.pendingState.GetNonce(from) == tx.Nonce() { return pool.promoteSpecialTx(from, tx) } // If the transaction pool is full, discard underpriced transactions diff --git a/eth/backend.go b/eth/backend.go index 87896b32cf..16b360978f 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -20,7 +20,10 @@ package eth import ( "errors" "fmt" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/eth/filters" + "github.com/ethereum/go-ethereum/rlp" "math/big" "runtime" "sync" @@ -30,7 +33,6 @@ import ( "bytes" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/posv" @@ -41,7 +43,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/downloader" - "github.com/ethereum/go-ethereum/eth/filters" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -51,7 +52,6 @@ import ( "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/params" - "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rpc" ) @@ -208,12 +208,13 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { if eth.chainConfig.Posv != nil { c := eth.engine.(*posv.Posv) signHook := func(block *types.Block) error { - ok, err := eth.ValidateMasternode() + eb, err := eth.Etherbase() if err != nil { - return fmt.Errorf("Can't verify masternode permission: %v", err) + log.Error("Cannot get etherbase for append m2 header", "err", err) + return fmt.Errorf("etherbase missing: %v", err) } + ok := eth.txPool.IsSigner != nil && eth.txPool.IsSigner(eb) if !ok { - // silently return as this node doesn't have masternode permission to sign block return nil } if block.NumberU64()%common.MergeSignRange == 0 || !eth.chainConfig.IsTIP2019(block.Number()) { @@ -274,7 +275,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { start := time.Now() prevHeader := chain.GetHeaderByNumber(prevEpoc) penSigners := c.GetMasternodes(chain, prevHeader) - signedSigners := make(map[common.Address]*big.Int) if len(penSigners) > 0 { // Loop for each block to check missing sign. for i := prevEpoc; i < blockNumberEpoc; i++ { @@ -283,64 +283,27 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { bhash := bheader.Hash() block := chain.GetBlock(bhash, i) if len(penSigners) > 0 { - signer, err := c.RecoverSigner(block.Header()) + signedMasternodes, err := contracts.GetSignersFromContract(canonicalState, block) if err != nil { return nil, err } - for _, addr := range penSigners { - if signer == addr { - signedSigners[signer] = signedSigners[signer].Add(signedSigners[signer], big.NewInt(1)) + if len(signedMasternodes) > 0 { + // Check signer signed? + for _, signed := range signedMasternodes { + for j, addr := range penSigners { + if signed == addr { + // Remove it from dupSigners. + penSigners = append(penSigners[:j], penSigners[j+1:]...) + } + } } } } else { break } } - - if len(signedSigners) > 0 { - for signer, totalSign := range signedSigners { - if totalSign.Cmp(big.NewInt(4)) >= 0 { - for j, addr := range penSigners { - if signer == addr { - // If create block above 4 times then remove it from penSigners. - penSigners = append(penSigners[:j], penSigners[j+1:]...) - } - } - } - } - } } } - - // Check penalty signer return chain. - prevSigners := contracts.GetSignersFromBytes(prevHeader.Penalties) - if len(prevSigners) > 0 { - startCheck := blockNumberEpoc - common.RangeReturnSigner - data := make(map[common.Hash][]common.Address) - mapBlkHash := map[uint64]common.Hash{} - for curNumber := startCheck; curNumber < blockNumberEpoc; curNumber++ { - signers := make(map[common.Hash][]common.Address) - header := chain.GetHeaderByNumber(curNumber) - mapBlkHash[curNumber] = header.Hash() - data = contracts.GetSignersSignedAtBlockHash(c, chain, signers, header, curNumber) - } - - for _, blkHash := range mapBlkHash { - signers := data[blkHash] - for j, addr := range prevSigners { - for _, signer := range signers { - if signer == addr { - // If create block above 4 times then remove it from penSigners. - prevSigners = append(prevSigners[:j], prevSigners[j+1:]...) - } - } - } - } - if len(prevSigners) > 0 { - penSigners = append(penSigners, prevSigners...) - } - } - log.Debug("Time Calculated HookPenalty ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) return penSigners, nil } @@ -348,54 +311,108 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { } // Hook scans for bad masternodes and decide to penalty them - c.HookPenaltyTIPEVM = func(chain consensus.ChainReader, blockNumberEpoc uint64) ([]common.Address, error) { - canonicalState, err := eth.blockchain.State() - if canonicalState == nil || err != nil { - log.Crit("Can't get state at head of canonical chain", "head number", eth.blockchain.CurrentHeader().Number.Uint64(), "err", err) + c.HookPenaltyTIPSigning = func(chain consensus.ChainReader, header *types.Header, candidates []common.Address) ([]common.Address, error) { + prevEpoc := header.Number.Uint64() - chain.Config().Posv.Epoch + combackEpoch := uint64(0) + comebackLength := uint64((common.LimitPenaltyEpoch + 1) * chain.Config().Posv.Epoch) + if header.Number.Uint64() > comebackLength { + combackEpoch = header.Number.Uint64() - comebackLength } - prevEpoc := blockNumberEpoc - chain.Config().Posv.Epoch if prevEpoc >= 0 { start := time.Now() + + listBlockHash := make([]common.Hash, chain.Config().Posv.Epoch) + + // get list block hash & stats total created block + statMiners := make(map[common.Address]int) + listBlockHash[0] = header.ParentHash + parentnumber := header.Number.Uint64() - 1 + parentHash := header.ParentHash + for i := uint64(1); i < chain.Config().Posv.Epoch; i++ { + parentHeader := chain.GetHeader(parentHash, parentnumber) + miner, _ := c.RecoverSigner(parentHeader) + value, exist := statMiners[miner] + if exist { + value = value + 1 + } else { + value = 1 + } + statMiners[miner] = value + parentHash = parentHeader.ParentHash + parentnumber-- + listBlockHash[i] = parentHash + } + + // add list not miner to penalties prevHeader := chain.GetHeaderByNumber(prevEpoc) - penSigners := c.GetMasternodes(chain, prevHeader) - if len(penSigners) > 0 { - // Loop for each block to check missing sign. - blockHash := map[common.Hash]bool{} - for i := prevEpoc; i < blockNumberEpoc; i++ { - if len(penSigners) > 0 { - bheader := chain.GetHeaderByNumber(i) - bhash := bheader.Hash() - if i%common.MergeSignRange == 0 { - blockHash[bhash] = true + preMasternodes := c.GetMasternodes(chain, prevHeader) + penalties := []common.Address{} + for miner, total := range statMiners { + if total < common.MinimunMinerBlockPerEpoch { + log.Debug("Find a node not enough requirement create block", "addr", miner.Hex(), "total", total) + penalties = append(penalties, miner) + } + } + for _, addr := range preMasternodes { + if _, exist := statMiners[addr]; !exist { + log.Debug("Find a node don't create block", "addr", addr.Hex()) + penalties = append(penalties, addr) + } + } + + // get list check penalties signing block & list master nodes wil comeback + penComebacks := []common.Address{} + if combackEpoch > 0 { + combackHeader := chain.GetHeaderByNumber(combackEpoch) + penalties := common.ExtractAddressFromBytes(combackHeader.Penalties) + for _, penaltie := range penalties { + for _, addr := range candidates { + if penaltie == addr { + penComebacks = append(penComebacks, penaltie) } - signData, ok := c.BlockSigners.Get(bhash) - if !ok { - block := chain.GetBlock(bhash, i) - txs := block.Transactions() - signData = c.CacheSigner(bheader, txs); - } - txs := signData.([]*types.Transaction) - // Check signer signed? - for _, tx := range txs { - blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) - from := *tx.From() - if blockHash[blkHash] == true { - for j, addr := range penSigners { - if from == addr { - // Remove it from dupSigners. - penSigners = append(penSigners[:j], penSigners[j+1:]...) - break - } - } - } - } - } else { - break } } } - log.Debug("Time Calculated HookPenaltyTIPEVM ", "block", blockNumberEpoc, "time", common.PrettyDuration(time.Since(start))) - return penSigners, nil + + // Loop for each block to check missing sign. with comeback nodes + mapBlockHash := map[common.Hash]bool{} + for i := common.RangeReturnSigner - 1; i >= 0; i-- { + if len(penComebacks) > 0 { + blockNumber := header.Number.Uint64() - uint64(i) - 1 + bhash := listBlockHash[i] + if blockNumber%common.MergeSignRange == 0 { + mapBlockHash[bhash] = true + } + signData, ok := c.BlockSigners.Get(bhash) + if !ok { + block := chain.GetBlock(bhash, blockNumber) + txs := block.Transactions() + signData = c.CacheSigner(bhash, txs) + } + txs := signData.([]*types.Transaction) + // Check signer signed? + for _, tx := range txs { + blkHash := common.BytesToHash(tx.Data()[len(tx.Data())-32:]) + from := *tx.From() + if mapBlockHash[blkHash] { + for j, addr := range penComebacks { + if from == addr { + // Remove it from dupSigners. + penComebacks = append(penComebacks[:j], penComebacks[j+1:]...) + break + } + } + } + } + } else { + break + } + } + + log.Debug("Time Calculated HookPenaltyTIPSigning ", "block", header.Number, "hash", header.Hash().Hex(), "pen comeback nodes", len(penComebacks), "not enough miner", len(penalties), "time", common.PrettyDuration(time.Since(start))) + penalties = append(penalties, penComebacks...) + return penComebacks, nil + } return []common.Address{}, nil } @@ -473,7 +490,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { return nil } - eth.txPool.IsMasterNode = func(address common.Address) bool { + eth.txPool.IsSigner = func(address common.Address) bool { currentHeader := eth.blockchain.CurrentHeader() header := currentHeader // Sometimes, the latest block hasn't been inserted to chain yet @@ -721,7 +738,9 @@ func (s *Ethereum) StartStaking(local bool) error { return nil } -func (s *Ethereum) StopStaking() { s.miner.Stop() } +func (s *Ethereum) StopStaking() { + s.miner.Stop() +} func (s *Ethereum) IsStaking() bool { return s.miner.Mining() } func (s *Ethereum) Miner() *miner.Miner { return s.miner } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index dd9928d47b..06827f4834 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -963,7 +963,7 @@ func (s *PublicBlockChainAPI) rpcOutputBlockSigners(b *types.Block, ctx context. if prevCheckpointBlock != nil { masternodes := engine.GetMasternodesFromCheckpointHeader(prevCheckpointBlock.Header(), blockNumber, s.b.ChainConfig().Posv.Epoch) signedBlock, _ := s.b.BlockByNumber(ctx, rpc.BlockNumber(signedBlockNumber)) - if s.b.ChainConfig().IsTIPEVMSigner(latestBlockNumber) { + if s.b.ChainConfig().IsTIPSigning(latestBlockNumber) { signers, err = GetSignersFromBlocks(s.b, signedBlock.NumberU64(), signedBlock.Hash(), masternodes) } else { signers, err = contracts.GetSignersByExecutingEVM(common.HexToAddress(common.BlockSigners), client, signedBlock.Hash()) @@ -1662,7 +1662,7 @@ func GetSignersFromBlocks(b Backend, blockNumber uint64, blockHash common.Hash, for _, signtx := range signTxs { blkHash := common.BytesToHash(signtx.Data()[len(signtx.Data())-32:]) from := *signtx.From() - if blkHash == blockHash && mapMN[from] == true { + if blkHash == blockHash && mapMN[from] { addrs = append(addrs, from) delete(mapMN, from) } diff --git a/miner/worker.go b/miner/worker.go index 91ee30df56..b3b67b03a1 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -584,7 +584,7 @@ func (self *worker) commitNewWork() { if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 { misc.ApplyDAOHardFork(work.state) } - if self.config.IsTIPEVMSigner(header.Number) { + if common.TIPSigning.Cmp(header.Number) == 0 { work.state.DeleteAddress(common.HexToAddress(common.BlockSigners)) } // won't grasp txs at checkpoint @@ -677,7 +677,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB } if tx.To().Hex() == common.BlockSigners { if len(tx.Data()) < 68 { - log.Trace("Data special transaction invalid lenght", "hash", tx.Hash(), "data", len(tx.Data())) + log.Trace("Data special transaction invalid length", "hash", tx.Hash(), "data", len(tx.Data())) continue } blkNumber := binary.BigEndian.Uint64(tx.Data()[8:40]) diff --git a/params/config.go b/params/config.go index a8f4027109..2d275c61f7 100644 --- a/params/config.go +++ b/params/config.go @@ -217,8 +217,8 @@ func (c *ChainConfig) IsTIP2019(num *big.Int) bool { return isForked(common.TIP2019Block, num) } -func (c *ChainConfig) IsTIPEVMSigner(num *big.Int) bool { - return isForked(common.TIPEVMSignerBlock, num) +func (c *ChainConfig) IsTIPSigning(num *big.Int) bool { + return isForked(common.TIPSigning, num) } // GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice). diff --git a/trie/node.go b/trie/node.go index 4b76f2b559..2b70d75314 100644 --- a/trie/node.go +++ b/trie/node.go @@ -43,7 +43,7 @@ type ( Val Node flags nodeFlag } - HashNode []byte + HashNode []byte ValueNode []byte )