diff --git a/Makefile b/Makefile index 5386305632..ac5b5fc6d5 100644 --- a/Makefile +++ b/Makefile @@ -25,10 +25,18 @@ platon-with-mpc: platon-with-vc: build/build_deps.sh + build/build_snark.sh build/env.sh go run build/ci.go install -vc on ./cmd/platon @echo "Done building platon with vc." @echo "Run \"$(GOBIN)/platon\" to launch platon." +platon-with-mv: + build/build_deps.sh + build/build_snark.sh + build/env.sh go run build/ci.go install -mv on ./cmd/platon + @echo "Done building platon with vc." + @echo "Run \"$(GOBIN)/platon\" to launch platon." + swarm: build/env.sh go run build/ci.go install ./cmd/swarm @echo "Done building." @@ -48,8 +56,14 @@ all-with-mpc: all-with-vc: build/build_deps.sh + build/build_snark.sh build/env.sh go run build/ci.go install -vc on +all-with-mv: + build/build_deps.sh + build/build_snark.sh + build/env.sh go run build/ci.go install -mv on + android: build/env.sh go run build/ci.go aar --local @echo "Done building." diff --git a/build/build_snark.sh b/build/build_snark.sh index c0db730004..836f1f9502 100644 --- a/build/build_snark.sh +++ b/build/build_snark.sh @@ -18,8 +18,11 @@ Get_Dist_Name() elif grep -Eqi "Debian" /etc/issue || grep -Eq "Debian" /etc/*-release; then DISTRO='Debian' PM='apt' - elif grep -Eqi "Ubuntu" /etc/issue || grep -Eq "Ubuntu" /etc/*-release; then - DISTRO='Ubuntu' + elif grep -Eqi "Ubuntu 18.04" /etc/issue || grep -Eq "Ubuntu 18.04" /etc/*-release; then + DISTRO='Ubuntu18' + PM='apt' + elif grep -Eqi "Ubuntu 16.04" /etc/issue || grep -Eq "Ubuntu 16.04" /etc/*-release; then + DISTRO='Ubuntu16' PM='apt' elif grep -Eqi "Raspbian" /etc/issue || grep -Eq "Raspbian" /etc/*-release; then DISTRO='Raspbian' @@ -59,11 +62,18 @@ fi SF_BUILD=$root/vc/build MAKE="make" if [ `expr substr $(uname -s) 1 5` = "Linux" ]; then - if [ "$DISTRO" = "Ubuntu" ]; then + if [ "$DISTRO" = "Ubuntu16" ]; then + echo "Ubuntu 16.04 install lib" sudo apt-get install llvm-6.0-dev llvm-6.0 libclang-6.0-dev sudo apt-get install libgmpxx4ldbl libgmp-dev libprocps4-dev + sudo apt-get install libboost-all-dev libssl-dev + elif [ "$DISTRO" = "Ubuntu18" ]; then + echo "Ubuntu 18.04 install lib" + sudo apt-get install llvm-6.0-dev llvm-6.0 libclang-6.0-dev + sudo apt-get install libgmpxx4ldbl libgmp-dev libprocps-dev + sudo apt-get install libboost-all-dev libssl-dev elif [ "$DISTRO" = "CentOS" ]; then - sudo yum install -y llvm clang gmp procps + sudo yum install -y llvm clang gmp procps else echo "not support system $DISTRO" fi diff --git a/build/ci.go b/build/ci.go index 900c784f7a..63eee0f9b9 100644 --- a/build/ci.go +++ b/build/ci.go @@ -214,11 +214,12 @@ func main() { func doInstall(cmdline []string) { // ./cmd/platon var ( - arch = flag.String("arch", "", "Architecture to cross build for") - cc = flag.String("cc", "", "C compiler to cross build with") - mpc = flag.String("mpc", "off", "Switch of mpc , on for compiling MPC, off for without compiling") - vc = flag.String("vc", "off", "Switch of vc , on for compiling VC, off for without compiling") + arch = flag.String("arch", "", "Architecture to cross build for") + cc = flag.String("cc", "", "C compiler to cross build with") + mpc = flag.String("mpc", "off", "Switch of mpc , on for compiling MPC, off for without compiling") gcflags = flag.String("gcflags", "", "Turn off compiler code optimization and function inlining") + vc = flag.String("vc", "off", "Switch of vc , on for compiling VC, off for without compiling") + mv = flag.String("mv", "off", "Switch of mv , on for compilingMPC and VC, off for without compiling") ) flag.CommandLine.Parse(cmdline) env := build.Env() @@ -250,11 +251,14 @@ func doInstall(cmdline []string) { if *mpc == "on" { goinstall.Args = append(goinstall.Args, "-tags=mpcon") } + if *gcflags == "on" { + goinstall.Args = append(goinstall.Args, "-gcflags=-N -l") + } if *vc == "on" { goinstall.Args = append(goinstall.Args, "-tags=vcon") } - if *gcflags == "on" { - goinstall.Args = append(goinstall.Args, "-gcflags=-N -l") + if *mv == "on" { + goinstall.Args = append(goinstall.Args, "-tags=mpcon vcon") } goinstall.Args = append(goinstall.Args, packages...) build.MustRun(goinstall) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index d0643519fe..8ffcb10f08 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -607,7 +607,7 @@ var ( Value: "", } MPCActorFlag = cli.StringFlag{ - Name: "mpc.actor", + Name: "mpc.actor", Usage: "The address of actor to exec mpc compute", Value: "", } @@ -889,7 +889,6 @@ func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) { } } - // MakePasswordList reads password lines from the file specified by the global --password flag. func MakePasswordList(ctx *cli.Context) []string { path := ctx.GlobalString(PasswordFileFlag.Name) @@ -1244,12 +1243,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { switch { case ctx.GlobalBool(TestnetFlag.Name): if !ctx.GlobalIsSet(NetworkIdFlag.Name) { - cfg.NetworkId = 3 + cfg.NetworkId = 103 } cfg.Genesis = core.DefaultTestnetGenesisBlock() case ctx.GlobalBool(RinkebyFlag.Name): if !ctx.GlobalIsSet(NetworkIdFlag.Name) { - cfg.NetworkId = 4 + cfg.NetworkId = 104 } cfg.Genesis = core.DefaultRinkebyGenesisBlock() case ctx.GlobalBool(DeveloperFlag.Name): @@ -1413,7 +1412,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } cache := &core.CacheConfig{ - Disabled: /*ctx.GlobalString(GCModeFlag.Name) == "archive"*/ true, + Disabled:/*ctx.GlobalString(GCModeFlag.Name) == "archive"*/ true, TrieNodeLimit: eth.DefaultConfig.TrieCache, TrieTimeLimit: eth.DefaultConfig.TrieTimeout, } diff --git a/consensus/cbft/cbft.go b/consensus/cbft/cbft.go index 2e7c139806..2e2b10351b 100644 --- a/consensus/cbft/cbft.go +++ b/consensus/cbft/cbft.go @@ -343,12 +343,12 @@ func (lower *BlockExt) isAncestor(higher *BlockExt) bool { return false } -// findHighest finds the highest block from current start; If there are multiple highest blockExts, return the one that has most signs +// findHighest finds the highest block from current start; If there are multiple highest blockExts, returns the one that singed by self; if none of blocks signed by self, returns the one that has most signs func (cbft *Cbft) findHighest(current *BlockExt) *BlockExt { highest := current for _, child := range current.children { current := cbft.findHighest(child) - if current.block.NumberU64() > highest.block.NumberU64() || (current.block.NumberU64() == highest.block.NumberU64() && len(current.signs) > len(highest.signs)) { + if current.block.NumberU64() > highest.block.NumberU64() || (current.block.NumberU64() == highest.block.NumberU64() && (current.isSigned || len(current.signs) > len(highest.signs))) { highest = current } } @@ -525,6 +525,7 @@ func (cbft *Cbft) execute(ext *BlockExt, parent *BlockExt) error { sealHash := ext.block.Header().SealHash() cbft.blockChainCache.WriteReceipts(sealHash, receipts, ext.block.NumberU64()) cbft.blockChainCache.WriteStateDB(sealHash, state, ext.block.NumberU64()) + //cbft.blockChainCache.MarkBlockHash(ext.block.Hash()) } else { cbft.log.Error("execute block error", "hash", ext.block.Hash(), "number", ext.block.NumberU64(), "ParentHash", parent.block.Hash(), "err", err) return errors.New("execute block error") @@ -601,7 +602,7 @@ func (cbft *Cbft) setHighestLogical(highestLogical *BlockExt) { func SetBackend(blockChain *core.BlockChain, txPool *core.TxPool) { cbft.log.Debug("call SetBackend()") cbft.blockChain = blockChain - cbft.ppos.SetStartTimeOfEpoch(blockChain.Genesis().Time().Int64()) + cbft.ppos.SetStartTimeOfEpoch(blockChain.Genesis().Time().Int64() / 1000) currentBlock := blockChain.CurrentBlock() @@ -1252,8 +1253,6 @@ func (cbft *Cbft) cleanByNumber(upperLimit uint64) { } } - - // Author implements consensus.Engine, returning the Ethereum address recovered // from the signature in the header's extra-data section. func (cbft *Cbft) Author(header *types.Header) (common.Address, error) { @@ -1702,6 +1701,8 @@ func (cbft *Cbft) calTurn(timePoint int64, parentNumber *big.Int, parentHash com if consensusNodes == nil || len(consensusNodes) <= 0 { log.Error("calTurn consensusNodes is emtpy~") return false + } else if len(consensusNodes) == 1 { + return true } durationPerTurn := durationPerNode * int64(len(consensusNodes)) @@ -1792,12 +1793,12 @@ func toMilliseconds(t time.Time) int64 { func (cbft *Cbft) ShouldSeal(parentNumber *big.Int, parentHash common.Hash, commitNumber *big.Int) bool { cbft.log.Trace("call ShouldSeal()") - - consensusNodes := cbft.ConsensusNodes(parentNumber, parentHash, commitNumber) - if consensusNodes != nil && len(consensusNodes) == 1 { - return true - } - + + //consensusNodes := cbft.ConsensusNodes(parentNumber, parentHash, commitNumber) + //if consensusNodes != nil && len(consensusNodes) == 1 { + // return true + //} + inturn := cbft.inTurn(parentNumber, parentHash, commitNumber) if inturn { cbft.netLatencyLock.RLock() @@ -1812,7 +1813,6 @@ func (cbft *Cbft) ShouldSeal(parentNumber *big.Int, parentHash common.Hash, comm return inturn } - func (cbft *Cbft) CurrentNodes(parentNumber *big.Int, parentHash common.Hash, blockNumber *big.Int) []*discover.Node { return cbft.ppos.getCurrentNodes(parentNumber, parentHash, blockNumber) } @@ -1885,12 +1885,16 @@ func (cbft *Cbft) accumulateRewards(config *params.ChainConfig, state *state.Sta } var nodeId discover.NodeID var err error + log.Info("Call accumulateRewards block header", " extra: ", hexutil.Encode(header.Extra)) if ok := bytes.Equal(header.Extra[32:96], make([]byte, 64)); ok { + log.Warn("Call accumulateRewards block header extra[32:96] is empty!") nodeId = cbft.config.NodeID } else { - if nodeId, _, err = ecrecover(header); err!=nil { + if nodeId, _, err = ecrecover(header); err != nil { log.Error("Failed to Call accumulateRewards, ecrecover faile", " err: ", err) return + } else { + log.Info("Success ecrecover", " nodeid: ", nodeId.String()) } } @@ -1898,7 +1902,7 @@ func (cbft *Cbft) accumulateRewards(config *params.ChainConfig, state *state.Sta var can *types.Candidate if big.NewInt(0).Cmp(new(big.Int).Rem(header.Number, big.NewInt(BaseSwitchWitness))) == 0 { can, err = cbft.ppos.GetWitnessCandidate(state, nodeId, -1) - }else { + } else { can, err = cbft.ppos.GetWitnessCandidate(state, nodeId, 0) } if err != nil { @@ -1910,7 +1914,7 @@ func (cbft *Cbft) accumulateRewards(config *params.ChainConfig, state *state.Sta return } log.Info("Call accumulateRewards, GetTicket ", "TicketId: ", can.TicketId.Hex()) - ticket, err := cbft.ppos.ticketPool.GetTicket(state, can.TicketId) + ticket, err := cbft.ppos.GetTicket(state, can.TicketId) if nil != err { log.Error("Failed to Call accumulateRewards, GetTicket faile ", " err: ", err.Error()) return @@ -1965,4 +1969,4 @@ func GetAmount(number *big.Int) *big.Int { func (cbft *Cbft) ForEachStorage(state *state.StateDB, title string) { cbft.ppos.ForEachStorage(state, title) -} \ No newline at end of file +} diff --git a/consensus/cbft/ppos.go b/consensus/cbft/ppos.go index cdb5da5b47..ce1e3b2c37 100644 --- a/consensus/cbft/ppos.go +++ b/consensus/cbft/ppos.go @@ -15,6 +15,7 @@ import ( "math/big" "sync" "github.com/PlatONnetwork/PlatON-Go/core/ticketcache" + //"runtime/debug" ) type ppos struct { @@ -32,7 +33,7 @@ type ppos struct { // the candidateContext pool object pointer candidateContext *pposm.CandidatePoolContext // the ticket pool object pointer - ticketPool *pposm.TicketPool + ticketContext *pposm.TicketPoolContext // the ticket id list cache ticketidsCache *ticketcache.TicketTempCache } @@ -44,7 +45,7 @@ func newPpos(config *params.CbftConfig) *ppos { lastCycleBlockNum: 0, config: config.PposConfig, candidateContext: pposm.NewCandidatePoolContext(config.PposConfig), - ticketPool: pposm.NewTicketPool(config.PposConfig), + ticketContext: pposm.NewTicketPoolContext(config.PposConfig), } } @@ -131,7 +132,7 @@ func (d *ppos) consensusNodes(parentNumber *big.Int, parentHash common.Hash, blo d.lock.RLock() defer d.lock.RUnlock() - log.Warn("call consensusNodes", "parentNumber", parentNumber.Uint64(), "parentHash", parentHash, "blockNumber", blockNumber.Uint64()) + log.Debug("call consensusNodes", "parentNumber", parentNumber.Uint64(), "parentHash", parentHash, "blockNumber", blockNumber.Uint64()) nodeCache := d.nodeRound.getNodeCache(parentNumber, parentHash) d.printMapInfo("consensusNodes nodeCache", parentNumber.Uint64(), parentHash) if nodeCache != nil { @@ -170,9 +171,11 @@ func (d *ppos) SetStartTimeOfEpoch(startTimeOfEpoch int64) { // Announce witness func (d *ppos) Election(state *state.StateDB, parentHash common.Hash, currBlocknumber *big.Int) ([]*discover.Node, error) { // TODO + //log.Debug("Call stack", "Election stack", string(debug.Stack())) if nextNodes, err := d.candidateContext.Election(state, parentHash, currBlocknumber); nil != err { - log.Error("ppos election next witness", " err: ", err) - panic("Election error " + err.Error()) + log.Error("PPOS Election next witness", " err: ", err) + /*panic("Election error " + err.Error())*/ + return nil, err } else { //d.candidateContext.ForEachStorage(state, "PPOS Election finish,view stateDB content again ...") return nextNodes, nil @@ -182,6 +185,8 @@ func (d *ppos) Election(state *state.StateDB, parentHash common.Hash, currBlockn // switch next witnesses to current witnesses func (d *ppos) Switch(state *state.StateDB) bool { log.Info("Switch begin...") + // TODO + //log.Debug("Call stack", "Switch stack", string(debug.Stack())) if !d.candidateContext.Switch(state) { return false } @@ -272,7 +277,7 @@ func (d *ppos) SetCandidateContextOption(blockChain *core.BlockChain, initialNod log.Debug("【Reload the oldest block at startup】 ", "parentNum", parentNum, "parentHash", parentHash, "parentStateRoot", parentStateRoot.String()) if parentState, err := blockChain.StateAt(parentStateRoot, parentBigInt, parentHash); nil != err { log.Error("Failed to load parentStateDB by block", "currtenNum", currentNum, "Hash", currentHash.String(), "parentNum", parentNum, "Hash", parentHash.String(), "err", err) - //panic("Failed to load parentStateDB by block parentNum" + fmt.Sprint(parentNum) + ", Hash" + parentHash.String() + "err" + err.Error()) + panic("Failed to load parentStateDB by block parentNum" + fmt.Sprint(parentNum) + ", Hash" + parentHash.String() + "err" + err.Error()) }else { parent = parentState } @@ -282,7 +287,7 @@ func (d *ppos) SetCandidateContextOption(blockChain *core.BlockChain, initialNod log.Debug("【Reload the oldest block at startup】", "currentNum", currentNum, "currentHash", currentHash, "stateRoot", stateRoot.String()) if currntState, err := blockChain.StateAt(stateRoot, currentBigInt, currentHash); nil != err { log.Error("Failed to load currentStateDB by block", "currtenNum", currentNum, "Hash", currentHash.String(), "err", err) - //panic("Failed to load currentStateDB by block currentNum" + fmt.Sprint(currentNum) + ", Hash" + currentHash.String() + "err" + err.Error()) + panic("Failed to load currentStateDB by block currentNum" + fmt.Sprint(currentNum) + ", Hash" + currentHash.String() + "err" + err.Error()) }else { current = currntState } @@ -299,7 +304,7 @@ func (d *ppos) SetCandidateContextOption(blockChain *core.BlockChain, initialNod log.Debug("【Reload the front normal fast at startup】", "currentNum", currentNum, "currentHash", currentHash, "stateRoot", stateRoot.String()) if currntState, err := blockChain.StateAt(stateRoot, currentBigInt, currentHash); nil != err { log.Error("Failed to load stateDB by block", "currentNum", currentNum, "Hash", currentHash.String(), "err", err) - //panic("Failed to load stateDB by block currentNum" + fmt.Sprint(currentNum) + ", Hash" + currentHash.String() + "err" + err.Error()) + panic("Failed to load stateDB by block currentNum" + fmt.Sprint(currentNum) + ", Hash" + currentHash.String() + "err" + err.Error()) }else { if err := d.setGeneralNodeCache(currntState, parentNum, currentNum, parentHash, currentHash); nil != err { log.Error("Failed to setGeneralNodeCache", "currentNum", currentNum, "Hash", currentHash.String(), "err", err) @@ -350,9 +355,10 @@ func (d *ppos)buildGenesisRound(blockNumber uint64, blockHash common.Hash, initi } func (d *ppos)printMapInfo(title string, blockNumber uint64, blockHash common.Hash){ - res := d.nodeRound[blockNumber] + /*res := d.nodeRound[blockNumber] log.Debug(title + ":Traversing out the RoundNodes,num: " + fmt.Sprint(blockNumber) + ", hash: " + blockHash.String()) + if round, ok := res[blockHash]; ok { if nil != round.former{ pposm.PrintObject(title + ":Traversing out of the round,num: " + fmt.Sprint(blockNumber) + ", hash: " + blockHash.String() + ", previous round: start:" + round.former.start.String() + ", end:" + round.former.end.String() + ", nodes: ", round.former.nodes) @@ -365,7 +371,7 @@ func (d *ppos)printMapInfo(title string, blockNumber uint64, blockHash common.Ha } }else { log.Error(title + ":Traversing out of the round is NOT EXIST !!!!!!!!,num: " + fmt.Sprint(blockNumber) + ", hash: " + blockHash.String()) - } + }*/ } /** Method provided to the built-in contract call */ @@ -429,43 +435,43 @@ func (d *ppos) GetRefundInterval() uint64 { /** about ticketpool's method */ func (d *ppos) GetPoolNumber (state vm.StateDB) (uint64, error) { - return d.ticketPool.GetPoolNumber(state) + return d.ticketContext.GetPoolNumber(state) } func (d *ppos) VoteTicket (state vm.StateDB, owner common.Address, voteNumber uint64, deposit *big.Int, nodeId discover.NodeID, blockNumber *big.Int) ([]common.Hash, error) { - return d.ticketPool.VoteTicket(state, owner, voteNumber, deposit, nodeId, blockNumber) + return d.ticketContext.VoteTicket(state, owner, voteNumber, deposit, nodeId, blockNumber) } func (d *ppos) GetTicket(state vm.StateDB, ticketId common.Hash) (*types.Ticket, error) { - return d.ticketPool.GetTicket(state, ticketId) + return d.ticketContext.GetTicket(state, ticketId) } func (d *ppos) GetTicketList (state vm.StateDB, ticketIds []common.Hash) ([]*types.Ticket, error) { - return d.ticketPool.GetTicketList(state, ticketIds) + return d.ticketContext.GetTicketList(state, ticketIds) } func (d *ppos) GetCandidateTicketIds (state vm.StateDB, nodeId discover.NodeID) ([]common.Hash, error) { - return d.ticketPool.GetCandidateTicketIds(state, nodeId) + return d.ticketContext.GetCandidateTicketIds(state, nodeId) } func (d *ppos) GetCandidateEpoch (state vm.StateDB, nodeId discover.NodeID) (uint64, error) { - return d.ticketPool.GetCandidateEpoch(state, nodeId) + return d.ticketContext.GetCandidateEpoch(state, nodeId) } func (d *ppos) GetTicketPrice (state vm.StateDB) (*big.Int, error) { - return d.ticketPool.GetTicketPrice(state) + return d.ticketContext.GetTicketPrice(state) } func (d *ppos) GetCandidateAttach (state vm.StateDB, nodeId discover.NodeID) (*types.CandidateAttach, error) { - return d.ticketPool.GetCandidateAttach(state, nodeId) + return d.ticketContext.GetCandidateAttach(state, nodeId) } func (d *ppos) Notify (state vm.StateDB, blockNumber *big.Int) error { - return d.ticketPool.Notify(state, blockNumber) + return d.ticketContext.Notify(state, blockNumber) } func (d *ppos) StoreHash (state *state.StateDB) { - if err := d.ticketPool.CommitHash(state); nil != err { + if err := d.ticketContext.StoreHash(state); nil != err { log.Error("Failed to StoreHash", "err", err) panic("Failed to StoreHash err" + err.Error()) } diff --git a/consensus/cbft/roundcache.go b/consensus/cbft/roundcache.go index 36579ab068..723e2895cc 100644 --- a/consensus/cbft/roundcache.go +++ b/consensus/cbft/roundcache.go @@ -4,6 +4,7 @@ import ( "github.com/PlatONnetwork/PlatON-Go/common" "math/big" "github.com/PlatONnetwork/PlatON-Go/p2p/discover" + "github.com/PlatONnetwork/PlatON-Go/log" ) type roundCache map[uint64]map[common.Hash]*nodeCache @@ -87,5 +88,6 @@ func (r roundCache) setNodeCache (blockNumber *big.Int, blockHash common.Hash, c if baseIrrCountNum > 0 { delete(r, baseIrrCountNum) } + log.Debug("【Setting NodeCache】", "blocknumber", blockNumber.String(), "blockHash", blockHash) } diff --git a/core/blockchain.go b/core/blockchain.go index 5316851346..06ecbf4457 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -20,6 +20,7 @@ package core import ( "errors" "fmt" + "github.com/deckarep/golang-set" "github.com/PlatONnetwork/PlatON-Go/core/ticketcache" "io" "math/big" @@ -141,6 +142,9 @@ type BlockChain struct { shouldElectionFn shouldElectionFn shouldSwitchFn shouldSwitchFn attemptAddConsensusPeerFn attemptAddConsensusPeerFn + // modify by niuxiaojie + knownBlockHashes mapset.Set + knownBlockHashesLock sync.RWMutex } // NewBlockChain returns a fully initialised block chain using information @@ -174,6 +178,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par engine: engine, vmConfig: vmConfig, badBlocks: badBlocks, + knownBlockHashes: mapset.NewSet(), } bc.SetValidator(NewBlockValidator(chainConfig, bc, engine)) bc.SetProcessor(NewStateProcessor(chainConfig, bc, engine)) @@ -208,6 +213,21 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par return bc, nil } +// modify by niuxiaojie +func (bc *BlockChain) MarkBlockHash(hash common.Hash) bool { + bc.knownBlockHashesLock.Lock() + defer bc.knownBlockHashesLock.Unlock() + + if bc.knownBlockHashes.Contains(hash) { + return false + } + for bc.knownBlockHashes.Cardinality() >= 2048 { + bc.knownBlockHashes.Pop() + } + log.Info("【BlockChain MarkBlockHash】", "hash", hash) + return bc.knownBlockHashes.Add(hash) +} + func (bc *BlockChain) InitConsensusPeerFn(seFn shouldElectionFn, ssFn shouldSwitchFn, addFn attemptAddConsensusPeerFn) { bc.shouldElectionFn = seFn bc.shouldSwitchFn = ssFn @@ -263,13 +283,6 @@ func (bc *BlockChain) loadLastState() error { } } - // Issue a status log for the user - currentFastBlock := bc.CurrentFastBlock() - - log.Info("Loaded most recent local header", "number", currentHeader.Number, "hash", currentHeader.Hash(), "age", common.PrettyAge(time.Unix(currentHeader.Time.Int64(), 0))) - log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "age", common.PrettyAge(time.Unix(currentBlock.Time().Int64(), 0))) - log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "age", common.PrettyAge(time.Unix(currentFastBlock.Time().Int64(), 0))) - return nil } @@ -681,7 +694,7 @@ func (bc *BlockChain) Stop() { // - HEAD-127: So we have a hard limit on the number of blocks reexecuted if !bc.cacheConfig.Disabled { //ppos add -> commit memory ticket cache to disk - ticketcache.GetTicketidsCachePtr().Commit(bc.db) + ticketcache.GetTicketidsCachePtr().Commit(bc.db, bc.CurrentBlock().Number()) //eth... triedb := bc.stateCache.TrieDB() @@ -916,15 +929,15 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. externBn := block.Number() // Irrelevant of the canonical status, write the block itself to the database - rawdb.TicketCacheCommit(bc.db) + rawdb.TicketCacheCommit(bc.db, externBn) rawdb.WriteBlock(bc.db, block) r := state.IntermediateRoot(bc.chainConfig.IsEIP158(block.Number())) log.Debug("【WriteBlockWithState】,Before state.Commit:", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "root", r.String()) // TODO - if cbftEngine, ok := bc.engine.(consensus.Bft); ok { - cbftEngine.ForEachStorage(state, "【WriteBlockWithState】,Before state.Commit:") - } + //if cbftEngine, ok := bc.engine.(consensus.Bft); ok { + // cbftEngine.ForEachStorage(state, "【WriteBlockWithState】,Before state.Commit:") + //} root, err := state.Commit(bc.chainConfig.IsEIP158(block.Number())) if err != nil { @@ -935,9 +948,9 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. r = state.IntermediateRoot(bc.chainConfig.IsEIP158(block.Number())) log.Debug("【WriteBlockWithState】,After state.Commit:", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "root", r.String()) // TODO - if cbftEngine, ok := bc.engine.(consensus.Bft); ok { - cbftEngine.ForEachStorage(state, "【WriteBlockWithState】,After state.Commit:") - } + //if cbftEngine, ok := bc.engine.(consensus.Bft); ok { + // cbftEngine.ForEachStorage(state, "【WriteBlockWithState】,After state.Commit:") + //} triedb := bc.stateCache.TrieDB() @@ -948,9 +961,9 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types. return NonStatTy, err } log.Info("【archive node commit stateDB trie】", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "root", root.String()) - if cbftEngine, ok := bc.engine.(consensus.Bft); ok { - cbftEngine.ForEachStorage(state, "【WriteBlockWithState】,After writing the chain:") - } + //if cbftEngine, ok := bc.engine.(consensus.Bft); ok { + // cbftEngine.ForEachStorage(state, "【WriteBlockWithState】,After writing the chain:") + //} } else { log.Info("【non-archive node put stateDB trie】", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "root", root.String()) // Full but not archive node, do proper garbage collection @@ -1197,6 +1210,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty bc.reportBlock(block, nil, err) return i, events, coalescedLogs, err } + // Create a new statedb using the parent block and report an // error if it fails. var parent *types.Block @@ -1211,9 +1225,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty } root := state.IntermediateRoot(bc.Config().IsEIP158(block.Number())) log.Debug("【Node synchronization: call inserChain】Before executing the transaction", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "block.root", block.Root().Hex(), "Real-time state.root", root.Hex()) - if cbftEngine, ok := bc.engine.(consensus.Bft); ok { - cbftEngine.ForEachStorage(state, "【Node synchronization: call inserChain】, Before executing the transaction:") - } + //if cbftEngine, ok := bc.engine.(consensus.Bft); ok { + // cbftEngine.ForEachStorage(state, "【Node synchronization: call inserChain】, Before executing the transaction:") + //} // Process block using the parent state as reference point. receipts, logs, usedGas, err := bc.processor.Process(block, state, bc.vmConfig, common.Big1) if err != nil { @@ -1278,9 +1292,9 @@ func (bc *BlockChain) ProcessDirectly(block *types.Block, state *state.StateDB, root := state.IntermediateRoot(bc.Config().IsEIP158(block.Number())) log.Debug("【The Consensus node synchronization】Before executing the transaction", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "block.root", block.Root().Hex(), "Real-time state.root", root.Hex()) - if cbftEngine, ok := bc.engine.(consensus.Bft); ok { - cbftEngine.ForEachStorage(state, "【ProcessDirectly】,Before executing the transaction:") - } + //if cbftEngine, ok := bc.engine.(consensus.Bft); ok { + // cbftEngine.ForEachStorage(state, "【ProcessDirectly】,Before executing the transaction:") + //} // Process block using the parent state as reference point. receipts, logs, usedGas, err := bc.processor.Process(block, state, bc.vmConfig, blockInterval) if err != nil { diff --git a/core/blockchain_cache.go b/core/blockchain_cache.go index ff9e57b980..a0618b1e21 100644 --- a/core/blockchain_cache.go +++ b/core/blockchain_cache.go @@ -2,13 +2,14 @@ package core import ( "errors" + "fmt" "github.com/PlatONnetwork/PlatON-Go/common" "github.com/PlatONnetwork/PlatON-Go/consensus" "github.com/PlatONnetwork/PlatON-Go/core/state" "github.com/PlatONnetwork/PlatON-Go/core/types" "github.com/PlatONnetwork/PlatON-Go/log" - "sync" "math/big" + "sync" ) var ( @@ -81,8 +82,10 @@ func (bcc *BlockChainCache) ReadReceipts(sealHash common.Hash) []*types.Receipt func (bcc *BlockChainCache) GetState(header *types.Header) (*state.StateDB, error) { state := bcc.ReadStateDB(header.SealHash()) if state != nil { + log.Info("BlockChainCache GetState", "addr", fmt.Sprintf("%p", state), "root", header.Root) return state, nil } else { + log.Info("BlockChainCache GetState", "root", header.Root) return bcc.StateAt(header.Root, header.Number, header.Hash()) } } @@ -103,8 +106,13 @@ func (pbc *BlockChainCache) WriteReceipts(sealHash common.Hash, receipts []*type pbc.receiptsMu.Lock() defer pbc.receiptsMu.Unlock() obj, exist := pbc.receiptsCache[sealHash] - if exist && obj.blockNum == blockNum { - obj.receipts = append(obj.receipts, receipts...) + if exist { + if obj.blockNum == blockNum && len(obj.receipts) == len(receipts) { + log.Info("the receipts already in cache") + } else { + log.Warn("there maybe an error!", "blockNum", blockNum, "obj.blockNum", obj.blockNum, "len(obj.receipts)", len(obj.receipts), "len(receipts)", len(receipts)) + obj.receipts = append(obj.receipts, receipts...) + } } else if !exist { pbc.receiptsCache[sealHash] = &receiptsCache{receipts: receipts, blockNum: blockNum} } @@ -116,7 +124,8 @@ func (bcc *BlockChainCache) WriteStateDB(sealHash common.Hash, stateDB *state.St defer bcc.stateDBMu.Unlock() log.Info("Write a StateDB instance to the cache", "sealHash", sealHash, "blockNum", blockNum) if _, exist := bcc.stateDBCache[sealHash]; !exist { - bcc.stateDBCache[sealHash] = &stateDBCache{stateDB: stateDB, blockNum: blockNum} + stateDBCpy := stateDB.Copy() + bcc.stateDBCache[sealHash] = &stateDBCache{stateDB: stateDBCpy, blockNum: blockNum} } } @@ -158,17 +167,24 @@ func (bcc *BlockChainCache) clearStateDB(sealHash common.Hash) { // Get the StateDB instance of the corresponding block func (bcc *BlockChainCache) MakeStateDB(block *types.Block) (*state.StateDB, error) { // Create a StateDB instance from the blockchain based on stateRoot - if state, err := bcc.StateAt(block.Root(), block.Number(), block.Hash()); err == nil && state != nil { - return state, nil - }else if nil != err { - log.Warn("Failed to StateAt on MakeStateDB ...", "err", err) + log.Info("------make StateDB------", "GoRoutineID", common.CurrentGoRoutineID(), "number", block.NumberU64(), "hash", block.Hash(), "stateRoot", block.Root()) + curBlock := bcc.BlockChain.CurrentBlock() + if curBlock != nil { + log.Info("------current block------", "GoRoutineID", common.CurrentGoRoutineID(), "number", curBlock.NumberU64(), "hash", curBlock.Hash(), "stateRoot", curBlock.Root()) } + log.Info("---------recheck Block", "number", block.NumberU64(), "hash", block.Hash(), "root", block.Root()) + // Read and copy the stateDB instance in the cache sealHash := bcc.Engine().SealHash(block.Header()) log.Info("Read and copy the stateDB instance in the cache", "sealHash", sealHash, "blockHash", block.Hash(), "blockNum", block.NumberU64(), "stateRoot", block.Root()) if state := bcc.ReadStateDB(sealHash); state != nil { + log.Debug("MakeStateDB", "addr", fmt.Sprintf("%p", state)) //return state.Copy(), nil return state, nil + } + if state, err := bcc.StateAt(block.Root(), block.Number(), block.Hash()); err == nil && state != nil { + log.Info("---------recheck check Block", "addr", fmt.Sprintf("%p", state), "number", block.NumberU64(), "hash", block.Hash(), "root", block.Root()) + return state, nil } else { return nil, errMakeStateDB } diff --git a/core/genesis.go b/core/genesis.go index 51746784a3..497ee28226 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -30,12 +30,12 @@ import ( "github.com/PlatONnetwork/PlatON-Go/common/math" "github.com/PlatONnetwork/PlatON-Go/core/rawdb" "github.com/PlatONnetwork/PlatON-Go/core/state" + "github.com/PlatONnetwork/PlatON-Go/core/ticketcache" "github.com/PlatONnetwork/PlatON-Go/core/types" "github.com/PlatONnetwork/PlatON-Go/ethdb" "github.com/PlatONnetwork/PlatON-Go/log" "github.com/PlatONnetwork/PlatON-Go/params" "github.com/PlatONnetwork/PlatON-Go/rlp" - "github.com/PlatONnetwork/PlatON-Go/core/ticketcache" ) //go:generate gencodec -type Genesis -field-override genesisSpecMarshaling -out gen_genesis.go @@ -46,14 +46,14 @@ var errGenesisNoConfig = errors.New("genesis has no chain configuration") // Genesis specifies the header fields, state of a genesis block. It also defines hard // fork switch-over blocks through the chain configuration. type Genesis struct { - Config *params.ChainConfig `json:"config"` - Nonce uint64 `json:"nonce"` - Timestamp uint64 `json:"timestamp"` - ExtraData []byte `json:"extraData"` - GasLimit uint64 `json:"gasLimit" gencodec:"required"` - Mixhash common.Hash `json:"mixHash"` - Coinbase common.Address `json:"coinbase"` - Alloc GenesisAlloc `json:"alloc" gencodec:"required"` + Config *params.ChainConfig `json:"config"` + Nonce uint64 `json:"nonce"` + Timestamp uint64 `json:"timestamp"` + ExtraData []byte `json:"extraData"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + Mixhash common.Hash `json:"mixHash"` + Coinbase common.Address `json:"coinbase"` + Alloc GenesisAlloc `json:"alloc" gencodec:"required"` // These fields are used for consensus tests. Please don't use them // in actual genesis blocks. @@ -88,13 +88,13 @@ type GenesisAccount struct { // field type overrides for gencodec type genesisSpecMarshaling struct { - Nonce math.HexOrDecimal64 - Timestamp math.HexOrDecimal64 - ExtraData hexutil.Bytes - GasLimit math.HexOrDecimal64 - GasUsed math.HexOrDecimal64 - Number math.HexOrDecimal64 - Alloc map[common.UnprefixedAddress]GenesisAccount + Nonce math.HexOrDecimal64 + Timestamp math.HexOrDecimal64 + ExtraData hexutil.Bytes + GasLimit math.HexOrDecimal64 + GasUsed math.HexOrDecimal64 + Number math.HexOrDecimal64 + Alloc map[common.UnprefixedAddress]GenesisAccount } type genesisAccountMarshaling struct { @@ -299,45 +299,63 @@ func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big // DefaultGenesisBlock returns the Ethereum main net genesis block. func DefaultGenesisBlock() *Genesis { return &Genesis{ - Config: params.MainnetChainConfig, - Nonce: 0, // 66 - ExtraData: hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), - GasLimit: 3150000000, //5000 - Alloc: decodePrealloc(mainnetAllocData), + Config: params.MainnetChainConfig, + Nonce: 0, // 66 + ExtraData: hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), + GasLimit: 3150000000, //5000 + Alloc: decodePrealloc(mainnetAllocData), } } // DefaultTestnetGenesisBlock returns the Ropsten network genesis block. func DefaultTestnetGenesisBlock() *Genesis { + + initAddress1 := new(big.Int) + initAddress1.SetString("1000000000000000000000000000000000000000", 16) + + initBalance1 := new(big.Int) + initBalance1.SetString("52b7d2dcc80cd400000000", 16) + + initAddress2 := new(big.Int) + initAddress2.SetString("1fe1b73f7f592d6c054d62fad1cc55756c6949f9", 16) + + initBalance2 := new(big.Int) + initBalance2.SetString("295be96e640669720000000", 16) + return &Genesis{ - Config: params.TestnetChainConfig, - Nonce: 66, - ExtraData: hexutil.MustDecode("0x3535353535353535353535353535353535353535353535353535353535353535"), - GasLimit: 16777216, - Alloc: decodePrealloc(testnetAllocData), + Config: params.TestnetChainConfig, + Nonce: 0, + ExtraData: hexutil.MustDecode("0x00000000000000000000000000000000000000000000000000000000000000007a9ff113afc63a33d11de571a679f914983a085d1e08972dcb449a02319c1661b931b1962bce02dfc6583885512702952b57bba0e307d4ad66668c5fc48a45dfeed85a7e41f0bdee047063066eae02910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + GasLimit: 0x99947b760, + Timestamp: 1546300800000, //2019-01-01 00:00:00.000 + Alloc: map[common.Address]GenesisAccount{ + common.BigToAddress(initAddress1): {Balance: initBalance1}, + common.BigToAddress(initAddress2): {Balance: initBalance2}, + }, } } // DefaultRinkebyGenesisBlock returns the Rinkeby network genesis block. func DefaultRinkebyGenesisBlock() *Genesis { return &Genesis{ - Config: params.RinkebyChainConfig, - Timestamp: 1492009146, - ExtraData: hexutil.MustDecode("0x52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - GasLimit: 4700000, - Alloc: decodePrealloc(rinkebyAllocData), + Config: params.RinkebyChainConfig, + Timestamp: 1492009146, + ExtraData: hexutil.MustDecode("0x52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + GasLimit: 4700000, + Alloc: decodePrealloc(rinkebyAllocData), } } func DefaultGrapeGenesisBlock() *Genesis { return &Genesis{ - Config: params.GrapeChainConfig, - Timestamp: 1492009146, - ExtraData: hexutil.MustDecode("0x52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - GasLimit: 3150000000, - Alloc: decodePrealloc(testnetAllocData), + Config: params.GrapeChainConfig, + Timestamp: 1492009146, + ExtraData: hexutil.MustDecode("0x52657370656374206d7920617574686f7269746168207e452e436172746d616e42eb768f2244c8811c63729a21a3569731535f067ffc57839b00206d1ad20c69a1981b489f772031b279182d99e65703f0076e4812653aab85fca0f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), + GasLimit: 3150000000, + Alloc: decodePrealloc(testnetAllocData), } } + // DeveloperGenesisBlock returns the 'platon --dev' genesis block. Note, this must // be seeded with the func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis { @@ -347,9 +365,9 @@ func DeveloperGenesisBlock(period uint64, faucet common.Address) *Genesis { // Assemble and return the genesis with the precompiles and faucet pre-funded return &Genesis{ - Config: &config, - ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, 65)...), - GasLimit: 6283185, + Config: &config, + ExtraData: append(append(make([]byte, 32), faucet[:]...), make([]byte, 65)...), + GasLimit: 6283185, Alloc: map[common.Address]GenesisAccount{ common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256 diff --git a/core/ppos/candidate_context.go b/core/ppos/candidate_context.go index 7a9a675042..0ae818342a 100644 --- a/core/ppos/candidate_context.go +++ b/core/ppos/candidate_context.go @@ -119,3 +119,7 @@ func (c *CandidatePoolContext) UpdateElectedQueue(state vm.StateDB, currBlockNum func (c *CandidatePoolContext) ForEachStorage(state *state.StateDB, title string) { c.initCandidatePool().ForEachStorage(state, title) } + +func (c *CandidatePoolContext) GetLuckyTickets(state vm.StateDB, flag int) ([]common.Hash, error) { + return c.initCandidatePool().GetLuckyTickets(state, flag) +} diff --git a/core/ppos/candidate_state.go b/core/ppos/candidate_state.go index f0b900994c..6c6d0ac49d 100644 --- a/core/ppos/candidate_state.go +++ b/core/ppos/candidate_state.go @@ -18,6 +18,7 @@ import ( "strconv" "strings" "sync" + "bytes" ) var ( @@ -113,11 +114,16 @@ func NewCandidatePool(configs *params.PposConfig) *CandidatePool { // 1:init previous witness and current witness and next witness and immediate and reserve // 2: init all information func (c *CandidatePool) initDataByState(state vm.StateDB, flag int) error { - log.Info("init data by stateDB...", "flag", flag) + log.Info("init data by stateDB...", "statedb addr", fmt.Sprintf("%p", state)) + + parentRoutineID := fmt.Sprintf("%s", common.CurrentGoRoutineID()) + //loading candidates func loadWitFunc := func(title string, canMap candidateStorage, getIndexFn func(state vm.StateDB) ([]discover.NodeID, error), getInfoFn func(state vm.StateDB, id discover.NodeID) (*types.Candidate, error)) error { + + log.Debug("initDataByState by Getting "+title+" parent routine "+parentRoutineID, "statedb addr", fmt.Sprintf("%p", state)) var witnessIds []discover.NodeID if ids, err := getIndexFn(state); nil != err { log.Error("Failed to decode "+title+" witnessIds on initDataByState", " err", err) @@ -184,6 +190,7 @@ func (c *CandidatePool) initDataByState(state vm.StateDB, flag int) error { getInfoFn func(state vm.StateDB, id discover.NodeID) (*types.Candidate, error)) (types.CandidateQueue, error) { var witnessIds []discover.NodeID + log.Debug("initDataByState by Getting "+title+" parent routine "+parentRoutineID, "statedb addr", fmt.Sprintf("%p", state)) if ids, err := getIndexFn(state); nil != err { log.Error("Failed to decode "+title+"Ids on initDataByState", " err", err) return nil, err @@ -293,9 +300,9 @@ func (c *CandidatePool) initDataByState(state vm.StateDB, flag int) error { // pledge Candidate func (c *CandidatePool) SetCandidate(state vm.StateDB, nodeId discover.NodeID, can *types.Candidate) error { - defer func() { - c.ForEachStorage(state, "View State After SetCandidate ...") - }() + //defer func() { + // c.ForEachStorage(state, "View State After SetCandidate ...") + //}() var nodeIds []discover.NodeID c.lock.Lock() @@ -315,7 +322,7 @@ func (c *CandidatePool) SetCandidate(state vm.StateDB, nodeId discover.NodeID, c // Before each pledge, we need to check whether the current can deposit is not less // than the minimum can deposit when the corresponding queue to be placed is full. - if _, ok := c.checkDeposit(state, can); !ok { + if _, ok := c.checkDeposit(state, can, false); !ok { c.lock.Unlock() log.Warn("Failed to checkDeposit on SetCandidate", "nodeId", nodeId.String(), " err", DepositLowErr) return DepositLowErr @@ -331,7 +338,7 @@ func (c *CandidatePool) SetCandidate(state vm.StateDB, nodeId discover.NodeID, c c.lock.Unlock() //go ticketPool.DropReturnTicket(state, nodeIds...) if len(nodeIds) > 0 { - if err := ticketPool.DropReturnTicket(state, can.BlockNumber, nodeIds...); nil != err { + if err := tContext.DropReturnTicket(state, can.BlockNumber, nodeIds...); nil != err { log.Error("Failed to DropReturnTicket on SetCandidate ...") //return err } @@ -434,7 +441,7 @@ func (c *CandidatePool) setCandidateInfo(state vm.StateDB, nodeId discover.NodeI delInfoFn(state, can.CandidateId) // update reserve id index if ids, err := getIndexFn(state); nil != err { - log.Error("withdraw failed get"+title+"Index on setCandidateInfo", "err", err) + log.Error("Failed to get"+title+"Index on setCandidateInfo", "err", err) return err } else { //for i, id := range ids { @@ -446,7 +453,7 @@ func (c *CandidatePool) setCandidateInfo(state vm.StateDB, nodeId discover.NodeI } } if err := setIndexFn(state, ids); nil != err { - log.Error("withdraw failed set"+title+"Index on setCandidateInfo", "err", err) + log.Error("Failed to set"+title+"Index on setCandidateInfo", "err", err) return err } } @@ -488,9 +495,9 @@ func (c *CandidatePool) GetCandidateArr(state vm.StateDB, nodeIds ...discover.No // candidate withdraw from immediates or reserve elected candidates func (c *CandidatePool) WithdrawCandidate(state vm.StateDB, nodeId discover.NodeID, price, blockNumber *big.Int) error { - defer func() { - c.ForEachStorage(state, "View State After WithdrawCandidate ...") - }() + //defer func() { + // c.ForEachStorage(state, "View State After WithdrawCandidate ...") + //}() var nodeIds []discover.NodeID if arr, err := c.withdrawCandidate(state, nodeId, price, blockNumber); nil != err { return err @@ -499,7 +506,7 @@ func (c *CandidatePool) WithdrawCandidate(state vm.StateDB, nodeId discover.Node } //go ticketPool.DropReturnTicket(state, nodeIds...) if len(nodeIds) > 0 { - if err := ticketPool.DropReturnTicket(state, blockNumber, nodeIds...); nil != err { + if err := tContext.DropReturnTicket(state, blockNumber, nodeIds...); nil != err { log.Error("Failed to DropReturnTicket on WithdrawCandidate ...") } } @@ -507,7 +514,7 @@ func (c *CandidatePool) WithdrawCandidate(state vm.StateDB, nodeId discover.Node } func (c *CandidatePool) withdrawCandidate(state vm.StateDB, nodeId discover.NodeID, price, blockNumber *big.Int) ([]discover.NodeID, error) { - log.Info("WithdrawCandidate...", "nodeId", nodeId.String(), "price", price.String()) + log.Info("WithdrawCandidate...", "nodeId", nodeId.String(), "price", price.String(), "config.RefundBlockNumber", c.RefundBlockNumber) c.lock.Lock() defer c.lock.Unlock() if err := c.initDataByState(state, 2); nil != err { @@ -516,7 +523,7 @@ func (c *CandidatePool) withdrawCandidate(state vm.StateDB, nodeId discover.Node } if price.Cmp(new(big.Int).SetUint64(0)) <= 0 { - log.Error("withdraw failed price invalid", " price", price.String()) + log.Error("Failed to WithdrawCandidate price invalid", " price", price.String()) return nil, WithdrawPriceErr } // cache @@ -526,7 +533,7 @@ func (c *CandidatePool) withdrawCandidate(state vm.StateDB, nodeId discover.Node if imCan, ok := c.immediateCandidates[nodeId]; !ok || nil == imCan { reCan, ok := c.reserveCandidates[nodeId] if !ok || nil == reCan { - log.Error("withdraw failed current Candidate is empty") + log.Error("Failed to WithdrawCandidate current Candidate is empty") return nil, CandidateEmptyErr } else { can = reCan @@ -538,10 +545,12 @@ func (c *CandidatePool) withdrawCandidate(state vm.StateDB, nodeId discover.Node // check withdraw price if can.Deposit.Cmp(price) < 0 { - log.Error("withdraw failed refund price must less or equal deposit", "key", nodeId.String()) + log.Error("Failed to WithdrawCandidate refund price must less or equal deposit", "key", nodeId.String()) return nil, WithdrawPriceErr } else if can.Deposit.Cmp(price) == 0 { // full withdraw + log.Info("WithdrawCandidate into full withdraw", "canId", can.CandidateId.String(), "current can deposit", can.Deposit.String(), "withdraw price is", price.String()) + handleFunc := func(tiltle string, delInfoFn func(state vm.StateDB, candidateId discover.NodeID), getIndexFn func(state vm.StateDB) ([]discover.NodeID, error), setIndexFn func(state vm.StateDB, nodeIds []discover.NodeID) error) error { @@ -550,7 +559,7 @@ func (c *CandidatePool) withdrawCandidate(state vm.StateDB, nodeId discover.Node delInfoFn(state, nodeId) // update this id index if ids, err := getIndexFn(state); nil != err { - log.Error("withdraw failed get"+tiltle+"Index on full withdraw", "err", err) + log.Error("Failed to get"+tiltle+"Index on full withdraw on WithdrawCandidate", "err", err) return err } else { for i := 0; i < len(ids); i++ { @@ -561,7 +570,7 @@ func (c *CandidatePool) withdrawCandidate(state vm.StateDB, nodeId discover.Node } } if err := setIndexFn(state, ids); nil != err { - log.Error("withdraw failed set"+tiltle+"Index on full withdraw", "err", err) + log.Error("Failed to set"+tiltle+"Index on full withdraw on WithdrawCandidate", "err", err) return err } } @@ -581,12 +590,12 @@ func (c *CandidatePool) withdrawCandidate(state vm.StateDB, nodeId discover.Node // append to refund (defeat) trie if err := c.setDefeat(state, nodeId, can); nil != err { - log.Error("withdraw failed setDefeat on full withdraw", "err", err) + log.Error("Failed to setDefeat on full withdraw on WithdrawCandidate", "err", err) return nil, err } // update index of defeat on trie if err := c.setDefeatIndex(state); nil != err { - log.Error("withdraw failed setDefeatIndex on full withdraw", "err", err) + log.Error("Failed to setDefeatIndex on full withdraw on WithdrawCandidate", "err", err) return nil, err } @@ -596,8 +605,10 @@ func (c *CandidatePool) withdrawCandidate(state vm.StateDB, nodeId discover.Node // Only withdraw part of the refunds, need to reorder the immediate elected candidates // The remaining candiate price to update current candidate info + log.Info("WithdrawCandidate into withdraw a few", "canId", can.CandidateId.String(), "current can deposit", can.Deposit.String(), "withdraw price is", price.String()) + if err := c.checkWithdraw(can.Deposit, price); nil != err { - log.Error("withdraw failed price invalid", " price", price.String(), "err", err) + log.Error("Failed to price invalid on WithdrawCandidate", " price", price.String(), "err", err) return nil, err } @@ -620,7 +631,7 @@ func (c *CandidatePool) withdrawCandidate(state vm.StateDB, nodeId discover.Node // update current candidate if err := setInfoFn(state, nodeId, canNew); nil != err { - log.Error("withdraw failed set"+title+" on a few of withdraw", "err", err) + log.Error("Failed to set"+title+" on a few of withdraw on WithdrawCandidate", "err", err) return nil, err } @@ -639,7 +650,7 @@ func (c *CandidatePool) withdrawCandidate(state vm.StateDB, nodeId discover.Node } // update new index if err := setIndexFn(state, ids); nil != err { - log.Error("withdraw failed set"+title+"Index on a few of withdraw", "err", err) + log.Error("Failed to set"+title+"Index on a few of withdraw on WithdrawCandidate", "err", err) return nil, err } return candidateArr, nil @@ -674,12 +685,12 @@ func (c *CandidatePool) withdrawCandidate(state vm.StateDB, nodeId discover.Node } // the withdraw if err := c.setDefeat(state, nodeId, canDefeat); nil != err { - log.Error("withdraw failed setDefeat on a few of withdraw", "err", err) + log.Error("Failed to setDefeat on a few of withdraw on WithdrawCandidate", "err", err) return nil, err } // update index of defeat on trie if err := c.setDefeatIndex(state); nil != err { - log.Error("withdraw failed setDefeatIndex on a few of withdraw", "err", err) + log.Error("Failed to setDefeatIndex on a few of withdraw on WithdrawCandidate", "err", err) return nil, err } } @@ -764,7 +775,7 @@ func (c *CandidatePool) GetDefeat(state vm.StateDB, nodeId discover.NodeID) (typ defeat, ok := c.defeatCandidates[nodeId] if !ok { - log.Error("Candidate is empty") + log.Error("Failed to GetDefeat : Candidate is empty") return nil, nil } return defeat, nil @@ -847,10 +858,10 @@ func (c *CandidatePool) GetOwner(state vm.StateDB, nodeId discover.NodeID) commo // refund once func (c *CandidatePool) RefundBalance(state vm.StateDB, nodeId discover.NodeID, blockNumber *big.Int) error { - defer func() { - c.ForEachStorage(state, "View State After RefundBalance ...") - }() - log.Info("Call RefundBalance: curr nodeId = " + nodeId.String() + ",curr blocknumber:" + blockNumber.String()) + //defer func() { + // c.ForEachStorage(state, "View State After RefundBalance ...") + //}() + log.Info("Call RefundBalance: curr nodeId = " + nodeId.String() + ",curr blocknumber:" + blockNumber.String(), "config.RefundBlockNumber:", c.RefundBlockNumber) c.lock.Lock() defer c.lock.Unlock() if err := c.initDataByState(state, 2); nil != err { @@ -880,7 +891,7 @@ func (c *CandidatePool) RefundBalance(state vm.StateDB, nodeId discover.NodeID, for index := 0; index < len(canArr); index++ { can := canArr[index] sub := new(big.Int).Sub(blockNumber, can.BlockNumber) - log.Info("Check defeat detail", "nodeId:", nodeId.String(), "curr blocknumber:", blockNumber.String(), "setcandidate blocknumber:", can.BlockNumber.String(), " diff:", sub.String()) + log.Info("Check defeat detail", "nodeId:", nodeId.String(), "curr blocknumber:", blockNumber.String(), "setcandidate blocknumber:", can.BlockNumber.String(), " diff:", sub.String(), "config.RefundBlockNumber", c.RefundBlockNumber) if sub.Cmp(new(big.Int).SetUint64(c.RefundBlockNumber)) >= 0 { // allow refund delCanArr = append(delCanArr, can) canArr = append(canArr[:index], canArr[index+1:]...) @@ -897,7 +908,7 @@ func (c *CandidatePool) RefundBalance(state vm.StateDB, nodeId discover.NodeID, addr = can.Owner } else { if addr != can.Owner { - log.Info("Failed to refundbalance couse current nodeId had bind different owner address ", "nodeId", nodeId.String(), "addr1", addr.String(), "addr2", can.Owner) + //log.Error("Failed to refundbalance couse current nodeId had bind different owner address ", "nodeId", nodeId.String(), "addr1", addr.String(), "addr2", can.Owner) if len(canArr) != 0 { canArr = append(delCanArr, canArr...) } else { @@ -924,7 +935,8 @@ func (c *CandidatePool) RefundBalance(state vm.StateDB, nodeId discover.NodeID, } // update the tire - if len(canArr) == 0 { + if len(canArr) == 0 { // full RefundBlockNumber + log.Info("Call RefundBalance Into full RefundBlockNumber ...", "nodeId", nodeId.String()) c.delDefeat(state, nodeId) if ids, err := getDefeatIdsByState(state); nil != err { for i := 0; i < len(ids); i++ { @@ -942,11 +954,14 @@ func (c *CandidatePool) RefundBalance(state vm.StateDB, nodeId discover.NodeID, setDefeatIdsState(state, value) } } else { + log.Debug("Current DefeatIndex is Empty, delete from state on RefundBalance ... ") setDefeatIdsState(state, []byte{}) } } } else { + log.Info("Call RefundBalance Into a few RefundBlockNumber ...", "nodeId", nodeId.String()) + PrintObject("Call RefundBalance Into a few RefundBlockNumber Remain Defeat Arr", canArr) // If have some remaining, update that if arrVal, err := rlp.EncodeToBytes(canArr); nil != err { log.Error("Failed to encode candidate object on RefundBalance", "key", nodeId.String(), "err", err) @@ -973,9 +988,9 @@ func (c *CandidatePool) RefundBalance(state vm.StateDB, nodeId discover.NodeID, // set elected candidate extra value func (c *CandidatePool) SetCandidateExtra(state vm.StateDB, nodeId discover.NodeID, extra string) error { - defer func() { - c.ForEachStorage(state, "View State After SetCandidateExtra ...") - }() + //defer func() { + // c.ForEachStorage(state, "View State After SetCandidateExtra ...") + //}() log.Info("Call SetCandidateExtra:", "nodeId", nodeId.String(), "extra", extra) c.lock.Lock() defer c.lock.Unlock() @@ -1007,9 +1022,9 @@ func (c *CandidatePool) SetCandidateExtra(state vm.StateDB, nodeId discover.Node // Announce witness func (c *CandidatePool) Election(state *state.StateDB, parentHash common.Hash, currBlockNumber *big.Int) ([]*discover.Node, error) { - defer func() { - c.ForEachStorage(state, "View State After Election ...") - }() + //defer func() { + // c.ForEachStorage(state, "View State After Election ...") + //}() var nodes []*discover.Node var cans types.CandidateQueue if nodeArr, canArr, err := c.election(state, parentHash); nil != err { @@ -1021,7 +1036,7 @@ func (c *CandidatePool) Election(state *state.StateDB, parentHash common.Hash, c nodeIds := make([]discover.NodeID, 0) for _, can := range cans { // Release lucky ticket TODO - if err := ticketPool.ReturnTicket(state, can.CandidateId, can.TicketId, currBlockNumber); nil != err { + if err := tContext.ReturnTicket(state, can.CandidateId, can.TicketId, currBlockNumber); nil != err { log.Error("Failed to ReturnTicket on Election", "nodeId", can.CandidateId.String(), "ticketId", can.TicketId.String(), "err", err) continue } @@ -1064,7 +1079,7 @@ func (c *CandidatePool) Election(state *state.StateDB, parentHash common.Hash, c // Release the lost list //go ticketPool.DropReturnTicket(state, nodeIds...) if len(nodeIds) > 0 { - if err := ticketPool.DropReturnTicket(state, currBlockNumber, nodeIds...); nil != err { + if err := tContext.DropReturnTicket(state, currBlockNumber, nodeIds...); nil != err { log.Error("Failed to DropReturnTicket on Election ...") } } @@ -1128,16 +1143,16 @@ func (c *CandidatePool) election(state *state.StateDB, parentHash common.Hash) ( if can, ok := nextWits[nodeId]; ok { // After election to call Selected LuckyTicket TODO - luckyId, err := ticketPool.SelectionLuckyTicket(state, nodeId, parentHash) + luckyId, err := tContext.SelectionLuckyTicket(state, nodeId, parentHash) if nil != err { log.Error("Failed to take luckyId on Election", "nodeId", nodeId.String(), "err", err) - return nil, nil, err + return nil, nil, errors.New(err.Error() + ", nodeId: " + nodeId.String()) } // Put the lucky ticket ID in the next witness details can.TicketId = luckyId if err := c.setNextWitness(state, nodeId, can); nil != err { - log.Error("failed to setNextWitness on election", "err", err) - return nil, nil, err + log.Error("Failed to setNextWitness on election", "nodeId", nodeId.String(), "err", err) + return nil, nil, errors.New(err.Error() + ", nodeId: " + nodeId.String()) } caches = append(caches, can) if node, err := buildWitnessNode(can); nil != err { @@ -1150,7 +1165,7 @@ func (c *CandidatePool) election(state *state.StateDB, parentHash common.Hash) ( } // update new nextwitnesses index if err := c.setNextWitnessIndex(state, nextWitIds); nil != err { - log.Error("failed to setNextWitnessIndex on election", "err", err) + log.Error("Failed to setNextWitnessIndex on election", "err", err) return nil, nil, err } // replace the next round of witnesses @@ -1323,9 +1338,12 @@ func (c *CandidatePool) GetAllWitness(state *state.StateDB) ([]*discover.Node, [ return nil, nil, nil, err } + parentRoutineID := fmt.Sprintf("%s", common.CurrentGoRoutineID()) + fetchWitnessFunc := func(title string, witnesses candidateStorage, getIndexFn func(state vm.StateDB) ([]discover.NodeID, error)) ([]*discover.Node, error) { + log.Debug("GetAllWitness by Getting "+title+" parent routine "+parentRoutineID, "statedb addr", fmt.Sprintf("%p", state)) nodes := make([]*discover.Node, 0) // caches @@ -1458,6 +1476,28 @@ func (c *CandidatePool) GetWitnessCandidate(state vm.StateDB, nodeId discover.No } } +func (c *CandidatePool) GetLuckyTickets(state vm.StateDB, flag int) ([]common.Hash, error) { + var witnessIds []discover.NodeID + if arr, err := c.getWitnessIndex(state); nil != err { + log.Error("Failed to getWitnessIndex on GetLuckyTickets", "err: ", err) + return nil, err + } else { + witnessIds = arr + } + luckyTicketArr := make([]common.Hash, 0) + for _, witnessId := range witnessIds { + can, err := c.GetWitnessCandidate(state, witnessId, flag) + if nil != err { + log.Error("Failed to getWitnessCandidate on GetLuckyTickets", "err: ", err) + return nil, err + } + if (common.Hash{}) != can.TicketId { + luckyTicketArr = append(luckyTicketArr, can.TicketId) + } + } + return luckyTicketArr, nil +} + func (c *CandidatePool) GetRefundInterval() uint64 { log.Info("Call GetRefundInterval", "RefundBlockNumber", c.RefundBlockNumber) return c.RefundBlockNumber @@ -1473,10 +1513,10 @@ func (c *CandidatePool) UpdateElectedQueue(state vm.StateDB, currBlockNumber *bi ids = arr } log.Info("Call UpdateElectedQueue SUCCESS !!!!!!!!! ") - c.ForEachStorage(state, "View State After UpdateElectedQueue ...") + //c.ForEachStorage(state, "View State After UpdateElectedQueue ...") //go ticketPool.DropReturnTicket(state, ids...) if len(ids) > 0 { - return ticketPool.DropReturnTicket(state, currBlockNumber, ids...) + return tContext.DropReturnTicket(state, currBlockNumber, ids...) } return nil } @@ -1491,7 +1531,7 @@ func (c *CandidatePool) updateQueue(state vm.StateDB, nodeIds ...discover.NodeID return nil, nil } if err := c.initDataByState(state, 1); nil != err { - // if err := c.initDataByState(state, 0); nil != err { + // if err := c.initDataByState(state, 0); nil != err { log.Error("Failed to initDataByState on UpdateElectedQueue", "err", err) return nil, err } @@ -1553,7 +1593,7 @@ func (c *CandidatePool) updateQueue(state vm.StateDB, nodeIds ...discover.NodeID delOldInfoFn(state, can.CandidateId) // update can's ids index if ids, err := getOldIndexFn(state); nil != err { - log.Error("withdraw failed get"+delTitle+"Index on UpdateElectedQueue", "nodeId", can.CandidateId.String(), "err", err) + log.Error("Failed to get"+delTitle+"Index on UpdateElectedQueue", "nodeId", can.CandidateId.String(), "err", err) return nil, nil, err } else { //for i, id := range ids { @@ -1565,7 +1605,7 @@ func (c *CandidatePool) updateQueue(state vm.StateDB, nodeIds ...discover.NodeID } } if err := setOldIndexFn(state, ids); nil != err { - log.Error("withdraw failed set"+delTitle+"Index on UpdateElectedQueue", "nodeId", can.CandidateId.String(), "err", err) + log.Error("Failed to set"+delTitle+"Index on UpdateElectedQueue", "nodeId", can.CandidateId.String(), "err", err) return nil, nil, err } } @@ -1612,7 +1652,7 @@ func (c *CandidatePool) updateQueue(state vm.StateDB, nodeIds ...discover.NodeID // update reserve id index if ids, err := getIndexFn(state); nil != err { - log.Error("withdraw failed get"+title+"Index on UpdateElectedQueue", "err", err) + log.Error("Failed to get"+title+"Index on UpdateElectedQueue", "err", err) return err } else { //for i, id := range ids { @@ -1624,7 +1664,7 @@ func (c *CandidatePool) updateQueue(state vm.StateDB, nodeIds ...discover.NodeID } } if err := setIndexFn(state, ids); nil != err { - log.Error("withdraw failed set"+title+"Index on UpdateElectedQueue", "err", err) + log.Error("Failed to set"+title+"Index on UpdateElectedQueue", "err", err) return err } } @@ -1640,7 +1680,7 @@ func (c *CandidatePool) updateQueue(state vm.StateDB, nodeIds ...discover.NodeID log.Debug("The current nodeId was originally in the Immediate ...") can := c.immediateCandidates[nodeId] //if !c.checkTicket(state.TCount(nodeId)) { // TODO - if tcount, noDrop := c.checkDeposit(state, can); !noDrop { // Direct drop + if tcount, noDrop := c.checkDeposit(state, can, true); !noDrop { // Direct drop if err := directdropFunc("Immediate", can, c.delImmediate, c.getImmediateIndex, c.setImmediateIndex); nil != err { return nil, err } else { @@ -1662,7 +1702,7 @@ func (c *CandidatePool) updateQueue(state vm.StateDB, nodeIds ...discover.NodeID log.Debug("The current nodeId was originally in the Reserve ...") can := c.reserveCandidates[nodeId] //if c.checkTicket(state.TCount(nodeId)) { // TODO - if tcount, noDrop := c.checkDeposit(state, can); !noDrop { // Direct drop + if tcount, noDrop := c.checkDeposit(state, can, true); !noDrop { // Direct drop if err := directdropFunc("Reserve", can, c.delReserve, c.getReserveIndex, c.setReserveIndex); nil != err { return nil, err } else { @@ -1696,7 +1736,7 @@ func (c *CandidatePool) preElectionReset(state vm.StateDB, can *types.Candidate) // it will drop the list directly, // but before the list is dropped, // it needs to determine which queue was in the queue. - if _, ok := c.checkDeposit(state, can); !ok { + if _, ok := c.checkDeposit(state, can, true); !ok { log.Warn("Failed to checkDeposit on preElectionReset", "nodeId", can.CandidateId.String(), " err", DepositLowErr) var del int // del: 1 del immiedate; 2 del reserve if _, ok := c.immediateCandidates[can.CandidateId]; ok { @@ -1726,7 +1766,7 @@ func (c *CandidatePool) preElectionReset(state vm.StateDB, can *types.Candidate) // update reserve id index if ids, err := getIndexFn(state); nil != err { - log.Error("withdraw failed get"+title+"Index on preElectionReset", "err", err) + log.Error("Failed to get"+title+"Index on preElectionReset", "err", err) return err } else { //for i, id := range ids { @@ -1738,7 +1778,7 @@ func (c *CandidatePool) preElectionReset(state vm.StateDB, can *types.Candidate) } } if err := setIndexFn(state, ids); nil != err { - log.Error("withdraw failed set"+title+"Index on preElectionReset", "err", err) + log.Error("Failed to set"+title+"Index on preElectionReset", "err", err) return err } } @@ -1774,7 +1814,7 @@ func (c *CandidatePool) checkFirstThreshold(can *types.Candidate) bool { // false: invalid deposit // true: pass -func (c *CandidatePool) checkDeposit(state vm.StateDB, can *types.Candidate) (bool, bool) { +func (c *CandidatePool) checkDeposit(state vm.StateDB, can *types.Candidate, holdself bool) (bool, bool) { tcount := c.checkTicket(state.TCount(can.CandidateId)) /** If the current number of votes meets the entry immediate pool @@ -1791,6 +1831,13 @@ func (c *CandidatePool) checkDeposit(state vm.StateDB, can *types.Candidate) (bo // z/100 == old * (100 + x) / 100 == old * (y%) tmp = new(big.Int).Div(tmp, big.NewInt(100)) if can.Deposit.Cmp(tmp) < 0 { + // If last is self and holdslef flag is true + // we must return true (Keep self on staying in the original queue) + if holdself && can.CandidateId == last.CandidateId { + log.Debug("The immeidate pool is full, and last is self and holdslef is true, Keep self on staying in the original queue", "current can nodeId", can.CandidateId.String(), "last can nodeId", last.CandidateId.String(), + "current can's Deposit:", can.Deposit.String(), "110% of the last can in the immediate pool:", tmp.String(), "the length of current immediate pool:", len(c.immediateCandidates), "the limit of Configuration:", c.maxCount) + return tcount, true + } log.Debug("The immeidate pool is full, and the current can's Deposit is less than 110% of the last can in the immediate pool.", "current can's Deposit:", can.Deposit.String(), "110% of the last can in the immediate pool:", tmp.String(), "the length of current immediate pool:", len(c.immediateCandidates), "the limit of Configuration:", c.maxCount) return tcount, false } @@ -1810,6 +1857,13 @@ func (c *CandidatePool) checkDeposit(state vm.StateDB, can *types.Candidate) (bo // z/100 == old * (100 + x) / 100 == old * (y%) tmp = new(big.Int).Div(tmp, big.NewInt(100)) if can.Deposit.Cmp(tmp) < 0 { + // If last is self and holdslef flag is true + // we must return true (Keep self on staying in the original queue) + if holdself && can.CandidateId == last.CandidateId { + log.Debug("The reserve pool is full, and last is self and holdslef is true, Keep self on staying in the original queue", "current can nodeId", can.CandidateId.String(), "last can nodeId", last.CandidateId.String(), + "current can's Deposit:", can.Deposit.String(), "110% of the last can in the reserve pool:", tmp.String(), "the length of current reserve pool:", len(c.reserveCandidates), "the limit of Configuration:", c.maxCount) + return tcount, true + } log.Debug("The reserve pool is full,and the current can's Deposit is less than 110% of the last can in the reserve pool.", "current can's Deposit:", can.Deposit.String(), "110% of the last can in the reserve pool:", tmp.String(), "the length of current reserve pool:", len(c.reserveCandidates), "the limit of Configuration:", c.maxCount) return tcount, false } @@ -1943,6 +1997,9 @@ func (c *CandidatePool) setDefeat(state vm.StateDB, candidateId discover.NodeID, //c.defeatCandidates[can.CandidateId] = defeatArrTmp defeatArr = defeatArrTmp } + + PrintObject("SetDefeat Arr, nodeId:" + candidateId.String() + " ,defeatArr", defeatArr) + // setting refund information on trie if value, err := rlp.EncodeToBytes(&defeatArr); nil != err { log.Error("Failed to encode candidate object on setDefeat", "key", candidateId.String(), "err", err) @@ -1971,10 +2028,15 @@ func (c *CandidatePool) setDefeatIndex(state vm.StateDB) error { // sort id sort.Strings(index) + PrintObject("SetDefeatIndex, After Sort defeat index String is", index) + for _, idStr := range index { id := indexMap[idStr] newdefeatIds = append(newdefeatIds, id) } + + PrintObject("SetDefeatIndex, After Sort defeat index is", newdefeatIds) + if len(newdefeatIds) == 0 { setDefeatIdsState(state, []byte{}) return nil @@ -2335,6 +2397,7 @@ func getDefeatsByState(state vm.StateDB, id discover.NodeID) (types.CandidateQue } func setDefeatState(state vm.StateDB, id discover.NodeID, val []byte) { + log.Debug("SetDefeatArr ... ...", "nodeId:", id.String(), "keyTrie:", buildKeyTrie(DefeatKey(id))) state.SetState(common.CandidatePoolAddr, DefeatKey(id), val) } @@ -2352,9 +2415,7 @@ func copyCandidateMapByIds(target, source candidateStorage, ids []discover.NodeI func PrintObject(s string, obj interface{}) { objs, _ := json.Marshal(obj) - log.Debug(s, "==", string(objs)) - //fmt.Println(s, string(objs)) } func buildWitnessNode(can *types.Candidate) (*discover.Node, error) { @@ -2376,7 +2437,8 @@ func makeCandidateSort(state vm.StateDB, arr types.CandidateQueue) { cand := make(types.CanConditions, 0) for _, can := range arr { tCount := state.TCount(can.CandidateId) - tprice := new(big.Int).Mul(big.NewInt(int64(tCount)), ticketPool.TicketPrice) + price, _ := tContext.GetTicketPrice(state) + tprice := new(big.Int).Mul(big.NewInt(int64(tCount)), price) money := new(big.Int).Add(can.Deposit, tprice) @@ -2518,3 +2580,10 @@ func (c *CandidatePool) ForEachStorage(state vm.StateDB, title string) { c.initDataByState(state, 2) c.lock.Unlock() } + +func buildKeyTrie (key []byte) string { + var buffer bytes.Buffer + buffer.Write(common.CandidatePoolAddr.Bytes()) + buffer.WriteString(string(key)) + return buffer.String() +} \ No newline at end of file diff --git a/core/ppos/ticket_context.go b/core/ppos/ticket_context.go new file mode 100644 index 0000000000..de3e12ab1f --- /dev/null +++ b/core/ppos/ticket_context.go @@ -0,0 +1,102 @@ +package pposm + +import ( + "github.com/PlatONnetwork/PlatON-Go/common" + "github.com/PlatONnetwork/PlatON-Go/core/types" + "github.com/PlatONnetwork/PlatON-Go/core/vm" + "github.com/PlatONnetwork/PlatON-Go/p2p/discover" + "github.com/PlatONnetwork/PlatON-Go/params" + "math/big" +) + +type TicketPoolContext struct { + Configs *params.PposConfig +} + +var tContext *TicketPoolContext + +// Initialize the global ticket pool context object +func NewTicketPoolContext(configs *params.PposConfig) *TicketPoolContext { + tContext = &TicketPoolContext{ + Configs: configs, + } + return tContext +} + +func GetTicketPoolContextPtr() *TicketPoolContext { + return tContext +} + +func (c *TicketPoolContext) initTicketPool() *TicketPool { + return NewTicketPool(c.Configs) +} + +func (c *TicketPoolContext) GetPoolNumber (state vm.StateDB) (uint64, error) { + return c.initTicketPool().GetPoolNumber(state) +} + +func (c *TicketPoolContext) VoteTicket (state vm.StateDB, owner common.Address, voteNumber uint64, deposit *big.Int, nodeId discover.NodeID, blockNumber *big.Int) ([]common.Hash, error) { + return c.initTicketPool().VoteTicket(state, owner, voteNumber, deposit, nodeId, blockNumber) +} + +func (c *TicketPoolContext) GetTicket(state vm.StateDB, ticketId common.Hash) (*types.Ticket, error) { + return c.initTicketPool().GetTicket(state, ticketId) +} + +func (c *TicketPoolContext) GetExpireTicketIds(state vm.StateDB, blockNumber *big.Int) ([]common.Hash, error) { + return c.initTicketPool().GetExpireTicketIds(state, blockNumber) +} + +func (c *TicketPoolContext) GetTicketList (state vm.StateDB, ticketIds []common.Hash) ([]*types.Ticket, error) { + return c.initTicketPool().GetTicketList(state, ticketIds) +} + +func (c *TicketPoolContext) GetCandidateTicketIds (state vm.StateDB, nodeId discover.NodeID) ([]common.Hash, error) { + return c.initTicketPool().GetCandidateTicketIds(state, nodeId) +} + +func (c *TicketPoolContext) GetCandidateEpoch (state vm.StateDB, nodeId discover.NodeID) (uint64, error) { + return c.initTicketPool().GetCandidateEpoch(state, nodeId) +} + +func (c *TicketPoolContext) GetTicketPrice (state vm.StateDB) (*big.Int, error) { + return c.initTicketPool().GetTicketPrice(state) +} + +func (c *TicketPoolContext) GetCandidateAttach (state vm.StateDB, nodeId discover.NodeID) (*types.CandidateAttach, error) { + return c.initTicketPool().GetCandidateAttach(state, nodeId) +} + +func (c *TicketPoolContext) Notify (state vm.StateDB, blockNumber *big.Int) error { + return c.initTicketPool().Notify(state, blockNumber) +} + +func (c *TicketPoolContext) StoreHash (state vm.StateDB) error { + return c.initTicketPool().CommitHash(state) +} + +func (c *TicketPoolContext) GetCandidatesTicketCount (state vm.StateDB, nodeIds []discover.NodeID) (map[discover.NodeID]int, error) { + return c.initTicketPool().GetCandidatesTicketCount(state, nodeIds) +} + +func (c *TicketPoolContext) GetCandidatesTicketIds (state vm.StateDB, nodeIds []discover.NodeID) (map[discover.NodeID][]common.Hash, error) { + return c.initTicketPool().GetCandidatesTicketIds(state, nodeIds) +} + +func (c *TicketPoolContext) DropReturnTicket(stateDB vm.StateDB, blockNumber *big.Int, nodeIds ...discover.NodeID) error { + return c.initTicketPool().DropReturnTicket(stateDB, blockNumber, nodeIds...) +} + +func (c *TicketPoolContext) ReturnTicket(stateDB vm.StateDB, nodeId discover.NodeID, ticketId common.Hash, blockNumber *big.Int) error { + return c.initTicketPool().ReturnTicket(stateDB, nodeId, ticketId, blockNumber) +} + +func (c *TicketPoolContext) SelectionLuckyTicket(stateDB vm.StateDB, nodeId discover.NodeID, blockHash common.Hash) (common.Hash, error) { + return c.initTicketPool().SelectionLuckyTicket(stateDB, nodeId, blockHash) +} + + + + + + diff --git a/core/ppos/ticket_state.go b/core/ppos/ticket_state.go index 6d3d57e340..296ae3b342 100644 --- a/core/ppos/ticket_state.go +++ b/core/ppos/ticket_state.go @@ -13,10 +13,12 @@ import ( "github.com/PlatONnetwork/PlatON-Go/params" "github.com/PlatONnetwork/PlatON-Go/rlp" "math/big" + "runtime" "sort" "strconv" "strings" "sync" + "fmt" ) var ( @@ -27,17 +29,14 @@ var ( DecodeTicketErr = errors.New("Decode Ticket error") DecodePoolNumberErr = errors.New("Decode SurplusQuantity error") RecordExpireTicketErr = errors.New("Record Expire Ticket error") - CandidateNotFindTicketErr = errors.New("The candidate no longer has this ticket") + CandidateNotFindErr = errors.New("The Candidate not find") CandidateNilTicketErr = errors.New("This candidate has no ticket") - GetCandidateTicketIdErr = errors.New("Get Candidate TicketIds error") - SetCandidateTicketIdErr = errors.New("Update Candidate TicketIds error") TicketPoolBalanceErr = errors.New("TicketPool not sufficient funds") - GetOwnerTicketIdsErr = errors.New("Get Owner TicketIds error") - SetOwnerTicketIdsErr = errors.New("Update Owner TicketIds error") TicketIdNotFindErr = errors.New("TicketId not find") HandleExpireTicketErr = errors.New("Failure to deal with expired tickets") GetCandidateAttachErr = errors.New("Get CandidateAttach error") SetCandidateAttachErr = errors.New("Update CandidateAttach error") + VoteTicketErr = errors.New("Voting failed") ) type TicketPool struct { @@ -50,25 +49,25 @@ type TicketPool struct { lock *sync.Mutex } -var ticketPool *TicketPool +//var ticketPool *TicketPool // initialize the global ticket pool object func NewTicketPool(configs *params.PposConfig) *TicketPool { - if nil != ticketPool { - return ticketPool - } - + //if nil != ticketPool { + // return ticketPool + //} + log.Debug("Build a New TicketPool Info ...") if "" == strings.TrimSpace(configs.TicketConfig.TicketPrice) { - configs.TicketConfig.TicketPrice = "1000000000000000000" + configs.TicketConfig.TicketPrice = "100000000000000000000" } var ticketPrice *big.Int if price, ok := new(big.Int).SetString(configs.TicketConfig.TicketPrice, 10); !ok { - ticketPrice, _ = new(big.Int).SetString("1000000000000000000", 10) + ticketPrice, _ = new(big.Int).SetString("100000000000000000000", 10) } else { ticketPrice = price } - ticketPool = &TicketPool{ + ticketPool := &TicketPool{ TicketPrice: ticketPrice, MaxCount: configs.TicketConfig.MaxCount, ExpireBlockNumber: configs.TicketConfig.ExpireBlockNumber, @@ -78,18 +77,19 @@ func NewTicketPool(configs *params.PposConfig) *TicketPool { } func (t *TicketPool) VoteTicket(stateDB vm.StateDB, owner common.Address, voteNumber uint64, deposit *big.Int, nodeId discover.NodeID, blockNumber *big.Int) ([]common.Hash, error) { - log.Debug("Start voting", "owner", owner.Hex(), "voteNumber", voteNumber, "price", deposit.Uint64(), "nodeId", nodeId.String(), "blockNumber", blockNumber.Uint64()) + log.Debug("Call Voting", "statedb addr", fmt.Sprintf("%p", stateDB)) + log.Info("Start Voting,VoteTicket", "owner", owner.Hex(), "voteNumber", voteNumber, "price", deposit.Uint64(), "nodeId", nodeId.String(), "blockNumber", blockNumber.Uint64()) voteTicketIdList, err := t.voteTicket(stateDB, owner, voteNumber, deposit, nodeId, blockNumber) if nil != err { log.Error("Voting failed", "nodeId", nodeId.String(), "voteNumber", voteNumber, "successNum", len(voteTicketIdList), "err", err) return voteTicketIdList, err } // Voting completed, candidates reordered - log.Debug("Successfully voted to start updating the list of candidates", "successNum", len(voteTicketIdList)) + log.Debug("Successfully voted to start updating the list of candidates,VoteTicket", "successNum", len(voteTicketIdList)) if err := cContext.UpdateElectedQueue(stateDB, blockNumber, nodeId); nil != err { log.Error("Failed to Update candidate when voteTicket success", "err", err) } - log.Debug("Successful vote, candidate list updated successfully", "successNum", len(voteTicketIdList)) + log.Debug("Successful vote, candidate list updated successfully,VoteTicket", "successNum", len(voteTicketIdList)) return voteTicketIdList, nil } @@ -102,7 +102,7 @@ func (t *TicketPool) voteTicket(stateDB vm.StateDB, owner common.Address, voteNu if nil != err { return voteTicketIdList, err } - log.Debug("Ticket pool", "surplusQuantity", surplusQuantity, "voteNumber", voteNumber, "blockNumber", blockNumber.Uint64()) + log.Debug("Execute voteTicket", "surplusQuantity", surplusQuantity, "voteNumber", voteNumber, "blockNumber", blockNumber.Uint64()) if surplusQuantity == 0 { log.Error("Ticket Insufficient quantity") return voteTicketIdList, TicketPoolNilErr @@ -110,45 +110,84 @@ func (t *TicketPool) voteTicket(stateDB vm.StateDB, owner common.Address, voteNu if surplusQuantity < voteNumber { voteNumber = surplusQuantity } - log.Debug("Start circular voting", "nodeId", nodeId.String()) + log.Debug("Start circular voting", "nodeId", nodeId.String(), "voteNumber", voteNumber) + + parentRoutineID := fmt.Sprintf("%s", common.CurrentGoRoutineID()) + + runtime.GOMAXPROCS(runtime.NumCPU()) + var wg sync.WaitGroup + wg.Add(int(voteNumber)) + type genTicket struct { + index uint64 + ticketId common.Hash + } + resultCh := make(chan genTicket, voteNumber) var i uint64 = 0 for ; i < voteNumber; i++ { - ticketId, err := generateTicketId(stateDB.TxHash(), i) - if err != nil { - return voteTicketIdList, err - } - ticket := &types.Ticket{ - TicketId: ticketId, - Owner: owner, - Deposit: deposit, - CandidateId: nodeId, - BlockNumber: blockNumber, - } - ticket.SetNormal() - voteTicketIdList = append(voteTicketIdList, ticketId) - if err := t.setTicket(stateDB, ticketId, ticket); err != nil { - return voteTicketIdList, err - } - log.Debug("setTicket succeeds, start recording tickets to expire", "blockNumber", blockNumber.Uint64(), "ticketId", ticketId.String()) - if err := t.recordExpireTicket(stateDB, blockNumber, ticketId); err != nil { - return voteTicketIdList, err - } - surplusQuantity, err := t.GetPoolNumber(stateDB) - if nil != err { - return voteTicketIdList, err - } - log.Debug("Record the success of the ticket to expire, and start reducing the number of tickets", "surplusQuantity", surplusQuantity) - if err := t.subPoolNumber(stateDB); err != nil { - return voteTicketIdList, err - } - surplusQuantity, err = t.GetPoolNumber(stateDB) - if nil != err { - return voteTicketIdList, err + go func(i uint64) { + + ticketId, _ := generateTicketId(stateDB.TxHash(), i) + + log.Debug("Call Voting parent routine " + parentRoutineID, "statedb addr", fmt.Sprintf("%p", stateDB), "ticketId", ticketId.String()) + + ticket := &types.Ticket{ + TicketId: ticketId, + Owner: owner, + Deposit: deposit, + CandidateId: nodeId, + BlockNumber: blockNumber, + } + ticket.SetNormal() + if err := t.setTicket(stateDB, ticketId, ticket); err != nil { + log.Error("Ticket information record failed", "ticketId", ticketId.Hex(), "err", err) + wg.Done() + return + } + genTicket := genTicket{ + index: i, + ticketId: ticketId, + } + resultCh <- genTicket + wg.Done() + }(i) + } + wg.Wait() + close(resultCh) + resultSize := len(resultCh) + if resultSize == 0 { + log.Error("Voting failed resultSize = 0", "err", err) + return voteTicketIdList, VoteTicketErr + } + voteTicketIdList = make([]common.Hash, voteNumber) + for result := range resultCh { + voteTicketIdList[result.index] = result.ticketId + } + if resultSize != int(voteNumber) { + list := make([]common.Hash, 0) + for i := 0; i < len(voteTicketIdList); i++ { + tid := voteTicketIdList[i] + if tid != (common.Hash{}) { + list = append(list, tid) + } } - log.Debug("Reduce the remaining amount of the ticket pool successfully", "surplusQuantity", surplusQuantity) + voteTicketIdList = list } - log.Debug("End loop voting", "nodeId", nodeId.String()) - stateDB.AppendTicketCache(nodeId, voteTicketIdList) + log.Debug("SetTicket succeeds, start recording tickets to expire", "blockNumber", blockNumber.Uint64(), "ticketAmount", len(voteTicketIdList)) + if err := t.recordExpireTicket(stateDB, blockNumber, voteTicketIdList); err != nil { + return voteTicketIdList, err + } + log.Debug("Record the success of the ticket to expire, and start reducing the number of tickets", "surplusQuantity", surplusQuantity) + if err := t.setPoolNumber(stateDB, surplusQuantity-uint64(len(voteTicketIdList))); err != nil { + return voteTicketIdList, err + } + surplusQuantity, err = t.GetPoolNumber(stateDB) + if nil != err { + return voteTicketIdList, err + } + + stateDB.AppendTicketCache(nodeId, voteTicketIdList[:]) + + log.Debug("Voting SUCCUESS !!!!!! Reduce the remaining amount of the ticket pool successfully", "surplusQuantity", surplusQuantity, "nodeId", nodeId.String()) return voteTicketIdList, nil } @@ -162,6 +201,7 @@ func (t *TicketPool) calcExpireBlockNumber(stateDB vm.StateDB, blockNumber *big. } func (t *TicketPool) GetExpireTicketIds(stateDB vm.StateDB, blockNumber *big.Int) ([]common.Hash, error) { + log.Debug("Call GetExpireTicketIds", "statedb addr", fmt.Sprintf("%p", stateDB)) var expireTicketIds []common.Hash if err := getTicketPoolState(stateDB, ExpireTicketKey((*blockNumber).Bytes()), &expireTicketIds); nil != err { return nil, err @@ -171,19 +211,19 @@ func (t *TicketPool) GetExpireTicketIds(stateDB vm.StateDB, blockNumber *big.Int // In the current block, // the ticket id is placed in the value slice with the block height as the key to find the expired ticket. -func (t *TicketPool) recordExpireTicket(stateDB vm.StateDB, blockNumber *big.Int, ticketId common.Hash) error { +func (t *TicketPool) recordExpireTicket(stateDB vm.StateDB, blockNumber *big.Int, ticketIds []common.Hash) error { expireTickets, err := t.GetExpireTicketIds(stateDB, blockNumber) if err != nil { - log.Error("recordExpireTicket error", "key", *blockNumber, "ticketId", ticketId.String(), "err", err) + log.Error("recordExpireTicket error", "key", blockNumber.Uint64(), "ticketIdSize", len(ticketIds), "err", err) return RecordExpireTicketErr } - expireTickets = append(expireTickets, ticketId) + expireTickets = append(expireTickets, ticketIds...) return t.setExpireTicket(stateDB, blockNumber, expireTickets) } func (t *TicketPool) setExpireTicket(stateDB vm.StateDB, blockNumber *big.Int, expireTickets []common.Hash) error { if value, err := rlp.EncodeToBytes(expireTickets); nil != err { - log.Error("Failed to encode ticketId object on setExpireTicket", "key", *blockNumber, "err", err) + log.Error("Failed to encode ticketId object on setExpireTicket", "key", blockNumber.Uint64(), "err", err) return EncodeTicketErr } else { setTicketPoolState(stateDB, ExpireTicketKey((*blockNumber).Bytes()), value) @@ -197,6 +237,9 @@ func (t *TicketPool) removeExpireTicket(stateDB vm.StateDB, blockNumber *big.Int if err != nil { return err } + if len(ticketIdList) == 0 { + return nil + } ticketIdList, success := removeTicketId(ticketId, ticketIdList) if !success { return TicketIdNotFindErr @@ -219,6 +262,9 @@ func (t *TicketPool) handleExpireTicket(stateDB vm.StateDB, expireBlockNumber *b if err != nil { return nil, err } + if ticket.TicketId == (common.Hash{}) { + continue + } candidateAttach, ok := candidateAttachMap[ticket.CandidateId] if !ok { tempCandidateAttach, err := t.GetCandidateAttach(stateDB, ticket.CandidateId) @@ -248,11 +294,12 @@ func (t *TicketPool) handleExpireTicket(stateDB vm.StateDB, expireBlockNumber *b // Get ticket list func (t *TicketPool) GetTicketList(stateDB vm.StateDB, ticketIds []common.Hash) ([]*types.Ticket, error) { + log.Debug("Call GetTickList", "statedb addr", fmt.Sprintf("%p", stateDB)) var tickets []*types.Ticket for _, ticketId := range ticketIds { ticket, err := t.GetTicket(stateDB, ticketId) if nil != err || ticket.TicketId == (common.Hash{}) { - log.Error("Did not find this ticket", "ticketId", ticketId) + log.Error("find this ticket fail", "ticketId", ticketId.Hex()) continue } tickets = append(tickets, ticket) @@ -262,6 +309,7 @@ func (t *TicketPool) GetTicketList(stateDB vm.StateDB, ticketIds []common.Hash) // Get ticket details based on TicketId func (t *TicketPool) GetTicket(stateDB vm.StateDB, ticketId common.Hash) (*types.Ticket, error) { + log.Debug("Call GetTicket", "statedb addr", fmt.Sprintf("%p", stateDB)) var ticket = new(types.Ticket) if err := getTicketPoolState(stateDB, ticketId.Bytes(), ticket); nil != err { return nil, DecodeTicketErr @@ -271,7 +319,7 @@ func (t *TicketPool) GetTicket(stateDB vm.StateDB, ticketId common.Hash) (*types func (t *TicketPool) setTicket(stateDB vm.StateDB, ticketId common.Hash, ticket *types.Ticket) error { if value, err := rlp.EncodeToBytes(ticket); nil != err { - log.Error("Failed to encode ticket object on setTicket", "key", ticketId.String(), "err", err) + log.Error("Failed to encode ticket object on setTicket", "key", ticketId.Hex(), "err", err) return EncodeTicketErr } else { setTicketPoolState(stateDB, ticketId.Bytes(), value) @@ -282,60 +330,88 @@ func (t *TicketPool) setTicket(stateDB vm.StateDB, ticketId common.Hash, ticket func (t *TicketPool) DropReturnTicket(stateDB vm.StateDB, blockNumber *big.Int, nodeIds ...discover.NodeID) error { t.lock.Lock() defer t.lock.Unlock() - log.Info("Start processing tickets for the drop list", "candidateNum", len(nodeIds)) + log.Debug("Call DropReturnTicket", "statedb addr", fmt.Sprintf("%p", stateDB)) + log.Info("Start processing tickets for the drop list on DropReturnTicket", "candidateNum", len(nodeIds), "blockNumber", blockNumber.Uint64()) for _, nodeId := range nodeIds { + if nodeId == (discover.NodeID{}) { + continue + } candidateTicketIds, err := t.GetCandidateTicketIds(stateDB, nodeId) if nil != err { return err } + if len(candidateTicketIds) == 0 { + continue + } candidateAttach, err := t.GetCandidateAttach(stateDB, nodeId) if nil != err { return err } candidateAttach.Epoch = new(big.Int).SetUint64(0) - log.Debug("Update candidate information", "nodeId", nodeId.String(), "epoch", candidateAttach.Epoch) + log.Debug("Update candidate information on DropReturnTicket", "nodeId", nodeId.String(), "epoch", candidateAttach.Epoch.Uint64()) if err := t.setCandidateAttach(stateDB, nodeId, candidateAttach); nil != err { return err } - log.Debug("Delete candidate ticket collection", "nodeId", nodeId.String(), "ticketSize", len(candidateTicketIds)) + log.Debug("Delete candidate ticket collection on DropReturnTicket", "nodeId", nodeId.String(), "ticketSize", len(candidateTicketIds)) if err := stateDB.RemoveTicketCache(nodeId, candidateTicketIds[:]); nil != err { return err } - log.Debug("Start processing each invalid ticket", "nodeId", nodeId.String(), "ticketSize", len(candidateTicketIds)) + surplusQuantity, err := t.GetPoolNumber(stateDB) + if nil != err { + return err + } + log.Debug("Start reducing the number of tickets on DropReturnTicket", "surplusQuantity", surplusQuantity, "candidateTicketIds", len(candidateTicketIds)) + if err := t.setPoolNumber(stateDB, surplusQuantity+uint64(len(candidateTicketIds))); err != nil { + return err + } + log.Debug("Start processing each invalid ticket on DropReturnTicket", "nodeId", nodeId.String(), "ticketSize", len(candidateTicketIds)) for _, ticketId := range candidateTicketIds { ticket, err := t.GetTicket(stateDB, ticketId) if nil != err { return err } + if ticket.TicketId == (common.Hash{}) { + continue + } ticket.SetInvalid(blockNumber) if err := t.setTicket(stateDB, ticketId, ticket); nil != err { return err } + if err := transfer(stateDB, common.TicketPoolAddr, ticket.Owner, ticket.Deposit); nil != err { + return err + } t.removeExpireTicket(stateDB, ticket.BlockNumber, ticketId) } } - log.Debug("End processing the list") + log.Debug("End processing the list on DropReturnTicket") return nil } func (t *TicketPool) ReturnTicket(stateDB vm.StateDB, nodeId discover.NodeID, ticketId common.Hash, blockNumber *big.Int) error { - log.Info("Release the selected ticket", "nodeId", nodeId.String(), "ticketId", ticketId.Hex(), "blockNumber", blockNumber.Uint64()) + log.Debug("Call ReturnTicket", "statedb addr", fmt.Sprintf("%p", stateDB)) + log.Info("Release the selected ticket on ReturnTicket", "nodeId", nodeId.String(), "ticketId", ticketId.Hex(), "blockNumber", blockNumber.Uint64()) t.lock.Lock() defer t.lock.Unlock() if ticketId == (common.Hash{}) { return TicketIdNotFindErr } + if nodeId == (discover.NodeID{}) { + return CandidateNotFindErr + } candidateAttach, err := t.GetCandidateAttach(stateDB, nodeId) if nil != err { return err } ticket, err := t.releaseTicket(stateDB, nodeId, candidateAttach, ticketId, blockNumber) + if ticket == nil { + return TicketIdNotFindErr + } ticket.SetSelected(blockNumber) - log.Debug("Update ticket", "state", ticket.State, "blockNumber", blockNumber.Uint64()) + log.Debug("Update ticket on ReturnTicket", "state", ticket.State, "blockNumber", blockNumber.Uint64()) if err := t.setTicket(stateDB, ticketId, ticket); nil != err { return err } - log.Debug("Update candidate total epoch", "nodeId", nodeId.String(), "epoch", candidateAttach.Epoch) + log.Debug("Update candidate total epoch on ReturnTicket", "nodeId", nodeId.String(), "epoch", candidateAttach.Epoch.Uint64()) if err := t.setCandidateAttach(stateDB, nodeId, candidateAttach); nil != err { return err } @@ -344,12 +420,14 @@ func (t *TicketPool) ReturnTicket(stateDB vm.StateDB, nodeId discover.NodeID, ti } func (t *TicketPool) releaseTicket(stateDB vm.StateDB, candidateId discover.NodeID, candidateAttach *types.CandidateAttach, ticketId common.Hash, blockNumber *big.Int) (*types.Ticket, error) { - log.Debug("Start executing releaseTicket", "nodeId", candidateId.String(), "ticketId", ticketId.Hex(), "epoch", candidateAttach.Epoch, "blockNumber", blockNumber.Uint64()) + log.Debug("Start executing releaseTicket", "nodeId", candidateId.String(), "ticketId", ticketId.Hex(), "epoch", candidateAttach.Epoch.Uint64(), "blockNumber", blockNumber.Uint64()) ticket, err := t.GetTicket(stateDB, ticketId) if nil != err { return ticket, err } - + if ticket.TicketId == (common.Hash{}) { + return nil, nil + } log.Debug("releaseTicket,Start Update", "nodeId", candidateId.String()) candidateTicketIds := make([]common.Hash, 0) candidateTicketIds = append(candidateTicketIds, ticketId) @@ -370,30 +448,31 @@ func (t *TicketPool) releaseTicket(stateDB vm.StateDB, candidateId discover.Node return ticket, err } log.Debug("releaseTicket, end the update ticket pool", "surplusQuantity", surplusQuantity) - log.Debug("releaseTicket, start updating the total epoch of candidates", "nodeId", candidateId.String(), "totalEpoch", candidateAttach.Epoch, "blockNumber", blockNumber.Uint64(), "ticketBlockNumber", ticket.BlockNumber.Uint64()) + log.Debug("releaseTicket, start updating the total epoch of candidates", "nodeId", candidateId.String(), "totalEpoch", candidateAttach.Epoch.Uint64(), "blockNumber", blockNumber.Uint64(), "ticketBlockNumber", ticket.BlockNumber.Uint64()) candidateAttach.SubEpoch(ticket.CalcEpoch(blockNumber)) - log.Debug("releaseTicket, the end of the update candidate total epoch", "nodeId", candidateId.String(), "totalEpoch", candidateAttach.Epoch, "blockNumber", blockNumber.Uint64(), "ticketBlockNumber", ticket.BlockNumber.Uint64()) - return ticket, nil + log.Debug("releaseTicket, the end of the update candidate total epoch", "nodeId", candidateId.String(), "totalEpoch", candidateAttach.Epoch.Uint64(), "blockNumber", blockNumber.Uint64(), "ticketBlockNumber", ticket.BlockNumber.Uint64()) + return ticket, transfer(stateDB, common.TicketPoolAddr, ticket.Owner, ticket.Deposit) } func (t *TicketPool) Notify(stateDB vm.StateDB, blockNumber *big.Int) error { + log.Debug("Call Notify", "statedb addr", fmt.Sprintf("%p", stateDB)) // Check expired tickets expireBlockNumber, ok := t.calcExpireBlockNumber(stateDB, blockNumber) - log.Debug("Check expired tickets", "isOk", ok, "expireBlockNumber", expireBlockNumber.Uint64()) + log.Debug("Check expired tickets on Notify", "isOk", ok, "expireBlockNumber", expireBlockNumber.Uint64()) if ok { if nodeIdList, err := t.handleExpireTicket(stateDB, expireBlockNumber, blockNumber); nil != err { - log.Error("OutBlockNotice method handleExpireTicket error", "blockNumber", *blockNumber, "err", err) + log.Error("OutBlockNotice method handleExpireTicket error", "blockNumber", blockNumber.Uint64(), "err", err) return HandleExpireTicketErr } else { // Notify the candidate to update the list information after processing the expired ticket - log.Debug("After processing the expired ticket, start updating the candidate list", "blockNumber", blockNumber.Uint64(), "nodeIdList", len(nodeIdList)) + log.Debug("After processing the expired ticket, start updating the candidate list on Notify", "blockNumber", blockNumber.Uint64(), "nodeIdList", len(nodeIdList)) if err := cContext.UpdateElectedQueue(stateDB, blockNumber, nodeIdList...); nil != err { log.Error("Failed to Update candidate when handleExpireTicket success on Notify", "err", err) } } } // Increase the total number of epoch for each candidate - log.Debug("Increase the total number of epoch for each candidate", "blockNumber", blockNumber.Uint64()) + log.Debug("Increase the total number of epoch for each candidate on Notify", "blockNumber", blockNumber.Uint64()) if err := t.calcCandidateEpoch(stateDB, blockNumber); nil != err { return err } @@ -426,8 +505,9 @@ func (t *TicketPool) calcCandidateEpoch(stateDB vm.StateDB, blockNumber *big.Int // According to the previous block Hash, // find the first ticket Id which is larger than the Hash. If not found, the last ticket Id is taken. func (t *TicketPool) SelectionLuckyTicket(stateDB vm.StateDB, nodeId discover.NodeID, blockHash common.Hash) (common.Hash, error) { + log.Debug("Call SelectionLuckyTicket", "statedb addr", fmt.Sprintf("%p", stateDB)) candidateTicketIds, err := t.GetCandidateTicketIds(stateDB, nodeId) - log.Debug("Start picking lucky tickets", "nodeId", nodeId.String(), "blockHash", blockHash.Hex(), "candidateTicketIds", len(candidateTicketIds)) + log.Debug("Start picking lucky tickets on SelectionLuckyTicket", "nodeId", nodeId.String(), "blockHash", blockHash.Hex(), "candidateTicketIds", len(candidateTicketIds)) luckyTicketId := common.Hash{} if nil != err { return luckyTicketId, err @@ -444,9 +524,9 @@ func (t *TicketPool) SelectionLuckyTicket(stateDB vm.StateDB, nodeId discover.No } sort.Float64s(decList) index := findFirstMatch(decList, hexutil.HexDec(blockHash.Hex()[2:])) - log.Debug("Pick out a lucky ticket", "index", index) + log.Debug("Pick out a lucky ticket on SelectionLuckyTicket", "index", index) luckyTicketId = decMap[decList[index]] - log.Debug("End the selection of lucky tickets", "nodeId", nodeId.String(), "blockHash", blockHash.Hex(), "luckyTicketId", luckyTicketId.Hex(), "candidateTicketIds", len(candidateTicketIds)) + log.Debug("End the selection of lucky tickets on SelectionLuckyTicket", "nodeId", nodeId.String(), "blockHash", blockHash.Hex(), "luckyTicketId", luckyTicketId.Hex(), "candidateTicketIds", len(candidateTicketIds)) return luckyTicketId, nil } @@ -510,6 +590,7 @@ func (t *TicketPool) GetPoolNumber(stateDB vm.StateDB) (uint64, error) { } func (t *TicketPool) GetCandidateTicketIds(stateDB vm.StateDB, nodeId discover.NodeID) ([]common.Hash, error) { + log.Debug("Call GetCandidaieTicketIds", "statedb addr", fmt.Sprintf("%p", stateDB)) candidateTicketIds, err := stateDB.GetTicketCache(nodeId) if nil != err { return nil, err @@ -518,6 +599,7 @@ func (t *TicketPool) GetCandidateTicketIds(stateDB vm.StateDB, nodeId discover.N } func (t *TicketPool) GetCandidatesTicketIds(stateDB vm.StateDB, nodeIds []discover.NodeID) (map[discover.NodeID][]common.Hash, error) { + log.Debug("Call GetCandidateArrTicketIds", "statedb addr", fmt.Sprintf("%p", stateDB)) result := make(map[discover.NodeID][]common.Hash) if nodeIds != nil { for _, nodeId := range nodeIds { @@ -531,7 +613,19 @@ func (t *TicketPool) GetCandidatesTicketIds(stateDB vm.StateDB, nodeIds []discov return result, nil } +func (t *TicketPool) GetCandidatesTicketCount(stateDB vm.StateDB, nodeIds []discover.NodeID) (map[discover.NodeID]int, error) { + log.Debug("Call GetCandidatesTicketCount", "statedb addr", fmt.Sprintf("%p", stateDB)) + result := make(map[discover.NodeID]int) + if nil != nodeIds { + for _, nodeId := range nodeIds { + result[nodeId] = int(stateDB.TCount(nodeId)) + } + } + return result, nil +} + func (t *TicketPool) GetCandidateAttach(stateDB vm.StateDB, nodeId discover.NodeID) (*types.CandidateAttach, error) { + log.Debug("Call GetCandidateAttach", "statedb addr", fmt.Sprintf("%p", stateDB)) candidateAttach := new(types.CandidateAttach) candidateAttach.Epoch = new(big.Int) if err := getTicketPoolState(stateDB, CandidateAttachKey(nodeId.Bytes()), candidateAttach); nil != err { @@ -543,7 +637,7 @@ func (t *TicketPool) GetCandidateAttach(stateDB vm.StateDB, nodeId discover.Node func (t *TicketPool) setCandidateAttach(stateDB vm.StateDB, nodeId discover.NodeID, candidateAttach *types.CandidateAttach) error { if value, err := rlp.EncodeToBytes(candidateAttach); nil != err { - log.Error("Failed to encode candidateAttach object on setCandidateAttach", "key", string(nodeId.Bytes()), "value", *candidateAttach, "err", err) + log.Error("Failed to encode candidateAttach object on setCandidateAttach", "key", string(nodeId.Bytes()), "value", candidateAttach.Epoch.Uint64(), "err", err) return SetCandidateAttachErr } else { setTicketPoolState(stateDB, CandidateAttachKey(nodeId.Bytes()), value) @@ -552,6 +646,7 @@ func (t *TicketPool) setCandidateAttach(stateDB vm.StateDB, nodeId discover.Node } func (t *TicketPool) GetCandidateEpoch(stateDB vm.StateDB, nodeId discover.NodeID) (uint64, error) { + log.Debug("Call GetCandidateEpoch", "statedb addr", fmt.Sprintf("%p", stateDB)) candidateAttach, err := t.GetCandidateAttach(stateDB, nodeId) if nil != err { return 0, err @@ -573,8 +668,25 @@ func (t *TicketPool) CommitHash(stateDB vm.StateDB) error { return nil } -func GetTicketPtr() *TicketPool { - return ticketPool +//func GetTicketPtr() *TicketPool { +// return ticketPool +//} + +func checkBalance(stateDB vm.StateDB, addr common.Address, amount *big.Int) bool { + if stateDB.GetBalance(addr).Cmp(amount) >= 0 { + return true + } + return false +} + +func transfer(stateDB vm.StateDB, from common.Address, to common.Address, amount *big.Int) error { + if !checkBalance(stateDB, from, amount) { + log.Error("TicketPool not sufficient funds", "from", from.Hex(), "to", to.Hex(), "money", amount.Uint64()) + return TicketPoolBalanceErr + } + stateDB.SubBalance(from, amount) + stateDB.AddBalance(to, amount) + return nil } func getTicketPoolState(stateDB vm.StateDB, key []byte, result interface{}) error { @@ -634,4 +746,4 @@ func findFirstMatch(list []float64, key float64) int { return len(list) - 1 } return left -} \ No newline at end of file +} diff --git a/core/ppos/ticket_state_test.go b/core/ppos/ticket_state_test.go index c458c20bf0..5776d2deef 100644 --- a/core/ppos/ticket_state_test.go +++ b/core/ppos/ticket_state_test.go @@ -47,9 +47,7 @@ func TestTicketProcess(t *testing.T) { candidatePoolContext := pposm.NewCandidatePoolContext(&configs) - ticketPool := pposm.NewTicketPool(&configs) - - t.Log("MaxCount", ticketPool.MaxCount, "ExpireBlockNumber", ticketPool.ExpireBlockNumber) + ticketPoolContext := pposm.NewTicketPoolContext(&configs) var state *state.StateDB if statedb, err := blockchain.State(); nil != err { @@ -97,12 +95,12 @@ func TestTicketProcess(t *testing.T) { if i == 2 { var tempBlockNumber uint64 = 6 for i := 0; i < 4; i++ { - ticketPool.Notify(state, new(big.Int).SetUint64(tempBlockNumber)) + ticketPoolContext.Notify(state, new(big.Int).SetUint64(tempBlockNumber)) tempBlockNumber++ } } - _, err := ticketPool.VoteTicket(state, voteOwner, 1, deposit, candidate.CandidateId, tempBlockNumber) + _, err := ticketPoolContext.VoteTicket(state, voteOwner, 1, deposit, candidate.CandidateId, tempBlockNumber) if nil != err { fmt.Println("vote ticket error:", err) } @@ -121,20 +119,20 @@ func TestTicketProcess(t *testing.T) { return } - ticketIds, err := ticketPool.GetCandidateTicketIds(state, candidate.CandidateId) + ticketIds, err := ticketPoolContext.GetCandidateTicketIds(state, candidate.CandidateId) if nil != err { t.Error("GetCandidateTicketIds error", err) } - ticketList, err := ticketPool.GetTicketList(state, ticketIds) + ticketList, err := ticketPoolContext.GetTicketList(state, ticketIds) - expireTicketIds, err := ticketPool.GetExpireTicketIds(state, blockNumber) + expireTicketIds, err := ticketPoolContext.GetExpireTicketIds(state, blockNumber) if nil != err { t.Error("GetExpireTicketIds error", err) } //expireTickets, err := ticketPool.GetTicketList(state, expireTicketIds) - surplusQuantity, err := ticketPool.GetPoolNumber(state) - candidateAttach, err := ticketPool.GetCandidateAttach(state, candidate.CandidateId) + surplusQuantity, err := ticketPoolContext.GetPoolNumber(state) + candidateAttach, err := ticketPoolContext.GetCandidateAttach(state, candidate.CandidateId) t.Logf("ticketPoolSize:[%d],expireTicketListSize:[%d],candidate.TicketPool:[%d],tcount:[%d],epoch:[%d]\n", surplusQuantity, len(expireTicketIds), len(ticketIds), state.TCount(candidate.CandidateId), candidateAttach.Epoch) @@ -145,28 +143,28 @@ func TestTicketProcess(t *testing.T) { } candidate, err = candidatePoolContext.GetCandidate(state, candidate.CandidateId) - ticketIds, err = ticketPool.GetCandidateTicketIds(state, candidate.CandidateId) + ticketIds, err = ticketPoolContext.GetCandidateTicketIds(state, candidate.CandidateId) if nil != err { t.Error("GetCandidateTicketIds error", err) } - expireTicketIds, err = ticketPool.GetExpireTicketIds(state, blockNumber) + expireTicketIds, err = ticketPoolContext.GetExpireTicketIds(state, blockNumber) if nil != err { t.Error("GetExpireTicketIds error", err) } - surplusQuantity, err = ticketPool.GetPoolNumber(state) - candidateAttach, err = ticketPool.GetCandidateAttach(state, candidate.CandidateId) + surplusQuantity, err = ticketPoolContext.GetPoolNumber(state) + candidateAttach, err = ticketPoolContext.GetCandidateAttach(state, candidate.CandidateId) t.Logf("ticketPoolSize:[%d],expireTicketListSize:[%d],candidate.TicketPool:[%d],tcount:[%d],epoch:[%d]\n", surplusQuantity, len(expireTicketIds), len(ticketIds), state.TCount(candidate.CandidateId), candidateAttach.Epoch) t.Logf("ticketPoolBalance[%v],ticketDetailBalance[%v]", state.GetBalance(common.TicketPoolAddr), state.GetBalance(common.TicketPoolAddr)) - if err := ticketPool.Notify(state, blockNumber); err != nil { + if err := ticketPoolContext.Notify(state, blockNumber); err != nil { t.Error("Execute HandleExpireTicket error", err) } blockHash := common.Hash{} blockHash.SetBytes([]byte("3b41e0aee38c1a1f959a6aaae678d86f1e6af59617d2f667bb2ef5527779c861")) - luckyTicketId, err := ticketPool.SelectionLuckyTicket(state, candidate.CandidateId, blockHash) + luckyTicketId, err := ticketPoolContext.SelectionLuckyTicket(state, candidate.CandidateId, blockHash) if nil != err { t.Error("SelectionLuckyTicket error", err) } @@ -174,20 +172,20 @@ func TestTicketProcess(t *testing.T) { //selectedTicketId := ticketList[selectedTicketIndex].TicketId t.Logf("-----------Start releasing a ticket 【%v】-----------\n", luckyTicketId.Hex()) tempTime := time.Now().UnixNano() / 1e6 - err = ticketPool.ReturnTicket(state, candidate.CandidateId, luckyTicketId, blockNumber) + err = ticketPoolContext.ReturnTicket(state, candidate.CandidateId, luckyTicketId, blockNumber) if nil != err { t.Error("ReleaseSelectedTicket error", err) } releaseTime = (time.Now().UnixNano() / 1e6) - tempTime - ticket, err := ticketPool.GetTicket(state, luckyTicketId) + ticket, err := ticketPoolContext.GetTicket(state, luckyTicketId) t.Logf("lucky ticket :%+v", ticket) - expireTicketIds, err = ticketPool.GetExpireTicketIds(state, blockNumber) + expireTicketIds, err = ticketPoolContext.GetExpireTicketIds(state, blockNumber) if nil != err { t.Error("GetExpireTicketIds error", err) } - surplusQuantity, err = ticketPool.GetPoolNumber(state) - candidateAttach, err = ticketPool.GetCandidateAttach(state, candidate.CandidateId) + surplusQuantity, err = ticketPoolContext.GetPoolNumber(state) + candidateAttach, err = ticketPoolContext.GetCandidateAttach(state, candidate.CandidateId) t.Logf("After processing the expired ticket block height:[%d]", blockNumber) t.Logf("ticketPoolSize:[%d],expireTicketListSize:[%d],candidate.TicketPool:[%d],tcount:[%d],epoch:[%d]\n", surplusQuantity, len(expireTicketIds), len(ticketIds), state.TCount(candidate.CandidateId), candidateAttach.Epoch) @@ -207,7 +205,7 @@ func TestTicketProcess(t *testing.T) { fmt.Println("When the first ticket is taken, the time taken for voting:", timeMap[1], "ms") } -func initParam() (*state.StateDB, *pposm.CandidatePoolContext, *pposm.TicketPool) { +func initParam() (*state.StateDB, *pposm.CandidatePoolContext, *pposm.TicketPoolContext) { var ( db = ethdb.NewMemDatabase() genesis = new(core.Genesis).MustCommit(db) @@ -233,7 +231,7 @@ func initParam() (*state.StateDB, *pposm.CandidatePoolContext, *pposm.TicketPool candidatePoolContextContext := pposm.NewCandidatePoolContext(&configs) - ticketPool := pposm.NewTicketPool(&configs) + ticketPoolContext := pposm.NewTicketPoolContext(&configs) var state *state.StateDB if statedb, err := blockchain.State(); nil != err { @@ -241,7 +239,7 @@ func initParam() (*state.StateDB, *pposm.CandidatePoolContext, *pposm.TicketPool } else { state = statedb } - return state, candidatePoolContextContext, ticketPool + return state, candidatePoolContextContext, ticketPoolContext } func TestTicketPool_VoteTicket(t *testing.T) { diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 20f502979e..0efcfe021c 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -370,6 +370,6 @@ func FindCommonAncestor(db DatabaseReader, a, b *types.Header) *types.Header { } //ppos add -> commit memory ticket cache to disk -func TicketCacheCommit(db ethdb.Database) { - ticketcache.GetTicketidsCachePtr().Commit(db) +func TicketCacheCommit(db ethdb.Database, currentBlockNumber *big.Int) { + ticketcache.GetTicketidsCachePtr().Commit(db, currentBlockNumber) } diff --git a/core/state/database.go b/core/state/database.go index c3174fa1a8..2a5e77fa37 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -18,6 +18,7 @@ package state import ( "fmt" + "github.com/PlatONnetwork/PlatON-Go/log" "sync" "github.com/PlatONnetwork/PlatON-Go/common" @@ -99,11 +100,16 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) { db.mu.Lock() defer db.mu.Unlock() + log.Info("------database OpenTrie------", "GoRoutineID", common.CurrentGoRoutineID(), "root", root) for i := len(db.pastTries) - 1; i >= 0; i-- { if db.pastTries[i].Hash() == root { + log.Info("------database OpenTrie pastTries----", "GoRoutineID", common.CurrentGoRoutineID(), "root", root) return cachedTrie{db.pastTries[i].Copy(), db}, nil } } + + log.Info("------database OpenTrie new trie------", "GoRoutineID", common.CurrentGoRoutineID(), "root", root) + tr, err := trie.NewSecure(root, db.db, MaxTrieCacheGen) if err != nil { return nil, err diff --git a/core/state/state_object.go b/core/state/state_object.go index 10b24ffecf..64ac50d2e8 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -19,9 +19,12 @@ package state import ( "bytes" + "encoding/hex" "fmt" + "github.com/PlatONnetwork/PlatON-Go/log" "io" "math/big" + "runtime/debug" "github.com/PlatONnetwork/PlatON-Go/common" "github.com/PlatONnetwork/PlatON-Go/crypto" @@ -128,6 +131,7 @@ type Account struct { // newObject creates a state object. func newObject(db *StateDB, address common.Address, data Account) *stateObject { + log.Debug("newObject", "state db addr", fmt.Sprintf("%p", db)) if data.Balance == nil { data.Balance = new(big.Int) } @@ -247,7 +251,10 @@ func (self *stateObject) GetCommittedState(db Database, key string) []byte { return value } } - + log.Debug("GetCommittedState", "stateObject addr", fmt.Sprintf("%p", self), "statedb addr", fmt.Sprintf("%p", self.db), "root", self.data.Root, "key", hex.EncodeToString([]byte(key))) + if self.data.Root == (common.Hash{}) { + log.Info("GetCommittedState", "stack", string(debug.Stack())) + } // Otherwise load the valueKey from trie enc, err := self.getTrie(db).TryGet([]byte(key)) if err != nil { @@ -268,6 +275,14 @@ func (self *stateObject) GetCommittedState(db Database, key string) []byte { } } + if valueKey != emptyStorage && len(value) == 0 { + log.Error("invalid storage valuekey", "key", hex.EncodeToString([]byte(key)), "valueKey", valueKey.String()) + return []byte{} + } + if len(value) == 0 && valueKey == emptyStorage { + log.Debug("empty storage valuekey", "key", hex.EncodeToString([]byte(key)), "valueKey", valueKey.String()) + } + log.Info("GetCommittedState", "stateObject addr", fmt.Sprintf("%p", self), "statedb addr", fmt.Sprintf("%p", self.db), "root", self.data.Root, "key", hex.EncodeToString([]byte(key)), "valueKey", valueKey.String(), "value", len(value)) self.originStorage[key] = valueKey self.originValueStorage[valueKey] = value return value @@ -277,7 +292,7 @@ func (self *stateObject) GetCommittedState(db Database, key string) []byte { // set [keyTrie,valueKey] to storage // set [valueKey,value] to db func (self *stateObject) SetState(db Database, keyTrie string, valueKey common.Hash, value []byte) { - + log.Debug("SetState ", "keyTrie", hex.EncodeToString([]byte(keyTrie)), "valueKey", valueKey, "value", hex.EncodeToString(value)) //if the new value is the same as old,don't set preValue := self.GetState(db, keyTrie) // get value key if bytes.Equal(preValue, value) { @@ -296,48 +311,13 @@ func (self *stateObject) SetState(db Database, keyTrie string, valueKey common.H } func (self *stateObject) setState(key string, valueKey common.Hash, value []byte) { + cpy := make([]byte, len(value)) + copy(cpy, value) self.dirtyStorage[key] = valueKey - self.dirtyValueStorage[valueKey] = value + self.dirtyValueStorage[valueKey] = cpy } // updateTrie writes cached storage modifications into the object's storage trie. -/*func (self *stateObject) updateTrie(db Database) Trie { - tr := self.getTrie(db) - for key, valueKey := range self.dirtyStorage { - - value, dirty := self.dirtyValueStorage[valueKey] - if dirty { - // Skip noop changes, persist actual changes - originValue, dirty2 := self.originValueStorage[valueKey] - if dirty2 { - if bytes.Equal(value, originValue) { - continue - } - } - } - - delete(self.dirtyStorage, key) - delete(self.dirtyValueStorage, valueKey) - - // Delete the value corresponding to the original valueKey - delete(self.originValueStorage, self.originStorage[key]) - - self.originStorage[key] = valueKey - self.originValueStorage[valueKey] = value - - if (valueKey == common.Hash{} || bytes.Equal(value, []byte{})) { - self.setError(tr.TryDelete([]byte(key))) - continue - } - - // Encoding []byte cannot fail, ok to ignore the error. - v, _ := rlp.EncodeToBytes(bytes.TrimLeft(valueKey[:], "\x00")) - self.setError(tr.TryUpdate([]byte(key), v)) - //self.setError(tr.TryUpdateValue(valueKey[:], value)) - } - return tr -}*/ - func (self *stateObject) updateTrie(db Database) Trie { tr := self.getTrie(db) for key, valueKey := range self.dirtyStorage { @@ -359,9 +339,9 @@ func (self *stateObject) updateTrie(db Database) Trie { //flush dirty value if value, ok := self.dirtyValueStorage[valueKey]; ok { - delete(self.originValueStorage, valueKey) + delete(self.dirtyValueStorage, valueKey) self.originValueStorage[valueKey] = value - self.setError(tr.TryUpdateValue(valueKey.Bytes(), v)) + self.setError(tr.TryUpdateValue(valueKey.Bytes(), value)) } } diff --git a/core/state/statedb.go b/core/state/statedb.go index 5ce4813ebc..8b2d04de12 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -19,20 +19,21 @@ package state import ( "bytes" - "errors" "fmt" + "github.com/PlatONnetwork/PlatON-Go/crypto/sha3" + "math/big" + "sort" + "sync" + + "encoding/json" "github.com/PlatONnetwork/PlatON-Go/common" "github.com/PlatONnetwork/PlatON-Go/core/ticketcache" "github.com/PlatONnetwork/PlatON-Go/core/types" "github.com/PlatONnetwork/PlatON-Go/crypto" - "github.com/PlatONnetwork/PlatON-Go/crypto/sha3" "github.com/PlatONnetwork/PlatON-Go/log" "github.com/PlatONnetwork/PlatON-Go/p2p/discover" "github.com/PlatONnetwork/PlatON-Go/rlp" "github.com/PlatONnetwork/PlatON-Go/trie" - "math/big" - "sort" - "sync" ) type revision struct { @@ -41,16 +42,13 @@ type revision struct { } var ( - storagePrefix = "storage-value-" // emptyState is the known hash of an empty state trie entry. emptyState = crypto.Keccak256Hash(nil) // emptyCode is the known hash of the empty EVM bytecode. - emptyCode = crypto.Keccak256Hash(nil) - emptyStorage = crypto.Keccak256Hash([]byte(storagePrefix)) + emptyCode = crypto.Keccak256Hash(nil) - //ppos add - ErrNotfindFromNodeId = errors.New("Not find tickets from node id") + emptyStorage = crypto.Keccak256Hash(nil) ) // StateDBs within the ethereum protocol are used to store anything @@ -98,6 +96,7 @@ type StateDB struct { // Create a new state from a given trie. //func New(root common.Hash, db Database) (*StateDB, error) { func New(root common.Hash, db Database, blocknumber *big.Int, blockhash common.Hash) (*StateDB, error) { + log.Debug("------statedb new------", "GoRoutineID", common.CurrentGoRoutineID(), "root", root) tr, err := db.OpenTrie(root) if err != nil { return nil, err @@ -145,18 +144,24 @@ func (self *StateDB) Reset(root common.Hash) error { return nil } -func (self *StateDB) AddLog(log *types.Log) { +func (self *StateDB) AddLog(logInfo *types.Log) { self.journal.append(addLogChange{txhash: self.thash}) - - log.TxHash = self.thash - log.BlockHash = self.bhash - log.TxIndex = uint(self.txIndex) - log.Index = self.logSize - self.logs[self.thash] = append(self.logs[self.thash], log) + // TODO + logsByte, _ := json.Marshal(logInfo) + log.Debug("【Call Add StateDB log】", "txHash", self.thash.Hex(), "log:", string(logsByte)) + logInfo.TxHash = self.thash + logInfo.BlockHash = self.bhash + logInfo.TxIndex = uint(self.txIndex) + logInfo.Index = self.logSize + self.logs[self.thash] = append(self.logs[self.thash], logInfo) self.logSize++ } func (self *StateDB) GetLogs(hash common.Hash) []*types.Log { + // TODO + logs := self.logs[hash] + logsByte, _ := json.Marshal(logs) + log.Debug("【Call Get StateDB Log】", "txHash", self.thash.Hex(), "logs:", string(logsByte)) return self.logs[hash] } @@ -364,13 +369,12 @@ func (self *StateDB) SetState(address common.Address, key, value []byte) { func getKeyValue(address common.Address, key []byte, value []byte) (string, common.Hash, []byte) { var buffer bytes.Buffer - buffer.WriteString(address.String()) + buffer.Write(address.Bytes()) buffer.WriteString(string(key)) keyTrie := buffer.String() //if value != nil && !bytes.Equal(value,[]byte{}){ buffer.Reset() - buffer.WriteString(storagePrefix) buffer.WriteString(string(value)) valueKey := common.Hash{} @@ -383,24 +387,6 @@ func getKeyValue(address common.Address, key []byte, value []byte) (string, comm //return keyTrie, common.Hash{}, value } - -/*func getKeyValue(address common.Address, key []byte, value []byte) (string, common.Hash, []byte) { - var buffer bytes.Buffer - buffer.WriteString(address.String()) - buffer.WriteString(string(key)) - keyTrie := buffer.String() - - //if value != nil && !bytes.Equal(value,[]byte{}){ - buffer.Reset() - buffer.WriteString(string(key)) - buffer.WriteString(string(value)) - valueKey := sha3.Sum256(buffer.Bytes()) - return keyTrie, valueKey, value - //} - //return keyTrie, common.Hash{}, value -}*/ - - // Suicide marks the given account as suicided. // This clears the account balance. // @@ -452,7 +438,7 @@ func (self *StateDB) getStateObject(addr common.Address) (stateObject *stateObje } return obj } - + log.Debug("getStateObject", "root addr", fmt.Sprintf("%p", self)) // Load the object from the database. enc, err := self.trie.TryGet(addr[:]) if len(enc) == 0 { @@ -476,6 +462,7 @@ func (self *StateDB) setStateObject(object *stateObject) { // Retrieve a state object or create a new state object if nil. func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject { + log.Debug("GetOrNewStateObject", "root addr", fmt.Sprintf("%p", self)) stateObject := self.getStateObject(addr) if stateObject == nil || stateObject.deleted { stateObject, _ = self.createObject(addr) @@ -657,9 +644,14 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { return s.trie.Hash() } +func (s *StateDB) Root() common.Hash { + return s.trie.Hash() +} + // Prepare sets the current transaction hash and index and block hash which is // used when the EVM emits new state logs. func (self *StateDB) Prepare(thash, bhash common.Hash, ti int) { + log.Debug("Prepare", "thash", thash.String()) self.thash = thash self.bhash = bhash self.txIndex = ti diff --git a/core/state_processor.go b/core/state_processor.go index de2c2fe9de..8f6eafeff0 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,6 +17,9 @@ package core import ( + "encoding/hex" + "encoding/json" + "fmt" "github.com/PlatONnetwork/PlatON-Go/common" "github.com/PlatONnetwork/PlatON-Go/consensus" "github.com/PlatONnetwork/PlatON-Go/consensus/misc" @@ -27,6 +30,7 @@ import ( "github.com/PlatONnetwork/PlatON-Go/params" "github.com/PlatONnetwork/PlatON-Go/log" "math/big" + "sync" ) // StateProcessor is a basic Processor, which takes care of transitioning @@ -37,6 +41,7 @@ type StateProcessor struct { config *params.ChainConfig // Chain configuration options bc *BlockChain // Canonical block chain engine consensus.Engine // Consensus engine used for block rewards + lock sync.Mutex } // NewStateProcessor initialises a new StateProcessor. @@ -71,14 +76,22 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg for i, tx := range block.Transactions() { statedb.Prepare(tx.Hash(), block.Hash(), i) receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg) + log.Debug("process tx receipt", "hash", tx.Hash(), "PostState", hex.EncodeToString(receipt.PostState), "bloom", hex.EncodeToString(receipt.Bloom.Bytes())) + for _, l := range receipt.Logs { + log.Debug("logs", "data", hex.EncodeToString(l.Data)) + } if err != nil { return nil, nil, 0, err } receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) } + + // TODO root := statedb.IntermediateRoot(p.bc.Config().IsEIP158(header.Number)) log.Debug("After executing the transaction,Before calling notify series func", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "block.root", block.Root().Hex(), "Real-time state.root", root.Hex()) + //log.Debug("After executing the transaction,Before calling notify series func", "receipt.root", types.DeriveSha(receipts), "bloom", types.CreateBloom(receipts)) + if cbftEngine, ok := p.bc.engine.(consensus.Bft); ok { // Notify call if err := cbftEngine.Notify(statedb, block.Number()); err != nil { @@ -102,12 +115,14 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // ppos Store Hash cbftEngine.StoreHash(statedb) } - root = statedb.IntermediateRoot(p.bc.Config().IsEIP158(header.Number)) - log.Debug("After executing the transaction, after calling the notify series func, before finalize", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "block.root", block.Root().Hex(), "Real-time state.root", root.Hex()) + //root = statedb.IntermediateRoot(p.bc.Config().IsEIP158(header.Number)) + //log.Debug("After executing the transaction, after calling the notify series func, before finalize", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "block.root", block.Root().Hex(), "Real-time state.root", root.Hex()) // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), receipts) - root = statedb.IntermediateRoot(p.bc.Config().IsEIP158(header.Number)) - log.Debug("After executing the transaction, after calling finalize", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "block.root", block.Root().Hex(), "Real-time state.root", root.Hex()) + // TODO + //root = statedb.IntermediateRoot(p.bc.Config().IsEIP158(header.Number)) + //log.Debug("After executing the transaction,After call finalize", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "block.root", block.Root().Hex(), "Real-time state.root", root.Hex()) + //log.Debug("After executing the transaction,After call finalize", "receipt.root", types.DeriveSha(receipts), "bloom", types.CreateBloom(receipts)) if cbftEngine, ok := p.bc.engine.(consensus.Bft); ok { // SetNodeCache @@ -117,8 +132,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg cbftEngine.SetNodeCache(statedb, parentNumber, blockNumber, block.ParentHash(), block.Hash()) // ppos Submit2Cache cbftEngine.Submit2Cache(statedb, blockNumber, blockInterval, block.Hash()) - root = statedb.IntermediateRoot(p.bc.Config().IsEIP158(header.Number)) - log.Debug("After executing the transaction, after calling Submit2Cache", "blockNumber", block.NumberU64(), "blockHash", block.Hash().Hex(), "block.root", block.Root().Hex(), "Real-time state.root", root.Hex()) } return receipts, allLogs, *usedGas, nil } @@ -137,6 +150,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmenv := vm.NewEVM(context, statedb, config, cfg) + log.Debug("ApplyTransaction", "statedb addr", fmt.Sprintf("%p", vmenv.StateDB)) // Apply the transaction to the current state (included in the env) _, gas, failed, err := ApplyMessage(vmenv, msg, gp) if err != nil { @@ -153,7 +167,6 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // 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 whether the root touch-delete accounts. - log.Debug("After Execute the transaction and start creating a receipt", "root", root, "failed", failed, "usedGas", *usedGas) receipt := types.NewReceipt(root, failed, *usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = gas @@ -164,6 +177,8 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // Set the receipt logs and create a bloom for filtering receipt.Logs = statedb.GetLogs(tx.Hash()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) - + log.Debug("Execution transaction", "statedb addr", fmt.Sprintf("%p", vmenv.StateDB), "txHash", tx.Hash().Hex(), "blocknumber", header.Number.Uint64(), "receipt.root", types.DeriveSha(types.Receipts{receipt}), "bloom", types.CreateBloom(types.Receipts{receipt})) + logsByte, _ := json.Marshal(receipt.Logs) + log.Debug("Execution transaction", "statedb addr", fmt.Sprintf("%p", vmenv.StateDB), "txHash", tx.Hash().Hex(), "blocknumber", header.Number.Uint64(), "logs", string(logsByte)) return receipt, gas, err } diff --git a/core/state_transition.go b/core/state_transition.go index f82f0ed7ce..7bac05c7dd 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -110,7 +110,7 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { //ppos evm.CandidatePoolContext = pposm.GetCandidateContextPtr() - evm.TicketPool = pposm.GetTicketPtr() + evm.TicketPoolContext = pposm.GetTicketPoolContextPtr() return &StateTransition{ gp: gp, evm: evm, diff --git a/core/ticketcache/ticketids_cache.go b/core/ticketcache/ticketids_cache.go index 83db245391..8354598ae6 100644 --- a/core/ticketcache/ticketids_cache.go +++ b/core/ticketcache/ticketids_cache.go @@ -47,9 +47,10 @@ var ( type TicketTempCache struct{ Cache *NumBlocks - RWlock *sync.RWMutex + lock *sync.Mutex } +// global obj of ticket related var ticketTemp *TicketTempCache //func NewTicketIdsCache(db ethdb.Database) *NumBlocks { @@ -69,7 +70,7 @@ func NewTicketIdsCache(db ethdb.Database) *TicketTempCache { NBlocks: make(map[string]*BlockNodes), }, - RWlock: &sync.RWMutex{}, + lock: &sync.Mutex{}, } if cache, err := db.Get(ticketPoolCacheKey); nil != err { @@ -85,9 +86,12 @@ func NewTicketIdsCache(db ethdb.Database) *TicketTempCache { return ticketTemp } +// Create a ticket cache by blocknumber and blockHash from global temp func GetNodeTicketsCacheMap(blocknumber *big.Int, blockhash common.Hash) (ret TicketCache) { log.Info("Call ticketcache GetNodeTicketsCacheMap", "blocknumber: ", blocknumber, " blockhash: ", blockhash.Hex()) if ticketTemp != nil { + + // getting a ticket cache by blocknumber and blockHash from global temp ret = ticketTemp.GetNodeTicketsMap(blocknumber, blockhash) } else { log.Warn("Failed call ticketcache GetNodeTicketsCacheMap, the Global ticketTemp instance is nil !!!!!!!!!!!!!!!") @@ -100,7 +104,7 @@ func GetTicketidsCachePtr() *TicketTempCache { } //////////////////////////// -func /*(t *TicketTempCache)*/ Hash(cache TicketCache) (common.Hash, error) { +func Hash(cache TicketCache) (common.Hash, error) { timer := Timer{} timer.Begin() @@ -116,23 +120,41 @@ func /*(t *TicketTempCache)*/ Hash(cache TicketCache) (common.Hash, error) { } func (t *TicketTempCache) GetNodeTicketsMap(blocknumber *big.Int, blockhash common.Hash) TicketCache { - t.RWlock.Lock() - defer t.RWlock.Unlock() + t.lock.Lock() + //defer t.lock.Unlock() log.Info("Call TicketTempCache GetNodeTicketsMap ...", "blocknumber: ", blocknumber, " blockhash: ", blockhash.Hex()) + + // a map (blocknumber => map[blockHash]map[nodeId][]ticketId) blockNodes, ok := t.Cache.NBlocks[blocknumber.String()] if !ok { blockNodes = &BlockNodes{} + // create a new map (map[blockHash]map[nodeId][]ticketId) blockNodes.BNodes = make(map[string]*NodeTicketIds) + // set to cache by current map (map[blockHash]map[nodeId][]ticketId) t.Cache.NBlocks[blocknumber.String()] = blockNodes + log.Error("Failed to GetNodeTicketsMap, TicketCache is empty by blocknumber", "blocknumber", blocknumber.String(), "blockHash", blockhash.String()) } + + // a map (blockHash => map[nodeId][]ticketId) nodeTicketIds, ok := blockNodes.BNodes[blockhash.String()] if !ok { nodeTicketIds = &NodeTicketIds{} + // create a new map (map[nodeId][]ticketId) nodeTicketIds.NTickets = make(map[string]*TicketIds) + // set to cache by current map (map[nodeId][]ticketId) blockNodes.BNodes[blockhash.String()] = nodeTicketIds + log.Error("Failed to GetNodeTicketsMap, TicketCache is empty by blockHash", "blocknumber", blocknumber.String(), "blockHash", blockhash.String()) } - //goroutine task + + if nil == nodeTicketIds.NTickets || len(nodeTicketIds.NTickets) == 0 { + log.Warn("Warn to GetNodeTicketsMap, TicketCache'NTickets is empty", "blocknumber", blocknumber.String(), "blockHash", blockhash.String()) + } + + /** + goroutine task + build data by global cache (map[nodeId][]ticketId) + */ type result struct { key discover.NodeID tids []common.Hash @@ -140,11 +162,18 @@ func (t *TicketTempCache) GetNodeTicketsMap(blocknumber *big.Int, blockhash comm resCh := make(chan *result, len(nodeTicketIds.NTickets)) var wg sync.WaitGroup wg.Add(len(nodeTicketIds.NTickets)) + + // key == nodeId + // value == []ticketId for k, v := range nodeTicketIds.NTickets { nid, err := discover.HexID(k) if err == nil { + // copy nodeId => []tickId by routine task go func(nodeid discover.NodeID, tidslice *TicketIds) { + // create a new []ticketId tids := make([]common.Hash, 0, len(tidslice.TicketId)) + + // recursive to build ticketId from global slice of ticketId for _, tid := range tidslice.TicketId { tids = append(tids, common.BytesToHash(tid)) } @@ -156,23 +185,31 @@ func (t *TicketTempCache) GetNodeTicketsMap(blocknumber *big.Int, blockhash comm }(nid, v) } else { wg.Done() - log.Error("Failed to TicketTempCache GetNodeTicketsMap: discover.HexID error ", "hex: ", k) + log.Error("Failed to TicketTempCache GetNodeTicketsMap: nodeId to discover.HexID error ", "NodeId: ", k, "blocknumber", blocknumber.String(), "blockHash", blockhash.String()) } } wg.Wait() close(resCh) + + t.lock.Unlock() + + /** + Build a new TicketCache + This TicketCache will be used in StateDB + */ out := NewTicketCache() for res := range resCh { + // a map type as nodeId => []ticketId out[res.key] = res.tids } return out } func (t *TicketTempCache) Submit2Cache(blocknumber, blockInterval *big.Int, blockhash common.Hash, in map[discover.NodeID][]common.Hash) { - t.RWlock.Lock() - defer t.RWlock.Unlock() + t.lock.Lock() + //defer t.lock.Unlock() - log.Info("Call TicketTempCache Submit2Cache ", "blocknumber: ", blocknumber, " blockInterval: ", blockInterval, " blockhash: ", blockhash.Hex(), " cachelen: ", len(t.Cache.NBlocks)) + log.Info("Call TicketTempCache Submit2Cache ", "blocknumber: ", blocknumber.String(), " blockInterval: ", blockInterval, " blockhash: ", blockhash.Hex(), " Before Submit2Cache, then cachelen: ", len(t.Cache.NBlocks)) blockNodes, ok := t.Cache.NBlocks[blocknumber.String()] if !ok { blockNodes = &BlockNodes{} @@ -210,32 +247,59 @@ func (t *TicketTempCache) Submit2Cache(blocknumber, blockInterval *big.Int, bloc blockNodes.BNodes[blockhash.String()] = nodeTicketIds t.Cache.NBlocks[blocknumber.String()] = blockNodes - //del old cache - number := new(big.Int).Sub(blocknumber, blockInterval) + //// tmp fix TODO + //if big.NewInt(0).Cmp(blockInterval) > 0 { + // log.Error("WARN WARN WARN !!! Call TicketTempCache Submit2Cache FINISH !!!!!! blockInterval is NEGATIVE NUMBER", "blocknumber: ", blocknumber.String(), " blockInterval: ", blockInterval, " blockhash: ", blockhash.Hex(), " After Submit2Cache, then cachelen: ", len(t.Cache.NBlocks)) + // return + //} + // + //interval := new(big.Int).Add(blockInterval, big.NewInt(20)) + // + ////del old cache + //number := new(big.Int).Sub(blocknumber, interval) + //for k := range t.Cache.NBlocks { + // if n, b := new(big.Int).SetString(k, 0); b { + // if n.Cmp(number) < 0 { + // delete(t.Cache.NBlocks, k) + // } + // } + //} + log.Info("Call TicketTempCache Submit2Cache FINISH !!!!!! ", "blocknumber: ", blocknumber.String(), " blockInterval: ", blockInterval, " blockhash: ", blockhash.Hex(), " After Submit2Cache, then cachelen: ", len(t.Cache.NBlocks)) + + t.lock.Unlock() +} + +func (t *TicketTempCache) Commit(db ethdb.Database, currentBlockNumber *big.Int) error { + t.lock.Lock() + //defer t.lock.Unlock() + log.Info("Call TicketTempCache Commit ...") + + timer := Timer{} + timer.Begin() + + // TODO tmp fix + interval := new(big.Int).Sub(currentBlockNumber, big.NewInt(30)) + log.Info("Call TicketTempCache Commit, Delete Global TicketIdsTemp key by", "currentBlockNumber", currentBlockNumber, "after calc interval", interval) for k := range t.Cache.NBlocks { if n, b := new(big.Int).SetString(k, 0); b { - if n.Cmp(number) < 0 { + if n.Cmp(interval) < 0 { delete(t.Cache.NBlocks, k) } } } - log.Info("Call TicketTempCache Submit2Cache finish ", "cachelen: ", len(t.Cache.NBlocks)) -} -func (t *TicketTempCache) Commit(db ethdb.Database) error { - t.RWlock.RLock() - defer t.RWlock.RUnlock() - log.Info("Call TicketTempCache Commit ...") + log.Info("Call TicketTempCache Commit, Delete Global TicketIdsTemp key FINISH !!!!", "currentBlockNumber", currentBlockNumber, "remian size after delete, then cachelen: ", len(t.Cache.NBlocks)) - timer := Timer{} - timer.Begin() out, err := proto.Marshal(t.Cache) + if err != nil { log.Error("Failted to TicketPoolCache Commit ", "ErrProbufMarshal: err", err.Error()) + t.lock.Unlock() return ErrProbufMarshal } - //logInfo("Marshal out: ", hexutil.Encode(out)) log.Info("Call TicketPoolCache Commit ", "cachelen: ", len(t.Cache.NBlocks), " outlen: ", len(out)) + t.lock.Unlock() + if err := db.Put(ticketPoolCacheKey, out); err != nil { log.Error("Failed to call TicketPoolCache Commit: level db put faile: ", "err", err.Error()) return ErrLeveldbPut @@ -251,6 +315,7 @@ func NewTicketCache() TicketCache { func (tc TicketCache) AppendTicketCache(nodeid discover.NodeID, tids []common.Hash) { value, ok := tc[nodeid] if !ok { + log.Warn("Warn to AppendTicketCache, the ticketIds is empty !!!!", "nodeId", nodeid.String()) value = make([]common.Hash, 0) } value = append(value, tids...) @@ -260,6 +325,7 @@ func (tc TicketCache) AppendTicketCache(nodeid discover.NodeID, tids []common.Ha func (tc TicketCache) GetTicketCache(nodeid discover.NodeID) ([]common.Hash, error) { tids, ok := tc[nodeid] if !ok { + log.Error("Failed to GetTicketCache, the ticketIds is empty !!!!", "nodeId", nodeid.String()) return nil, ErrNotfindFromNodeId } ret := make([]common.Hash, len(tids)) @@ -270,6 +336,7 @@ func (tc TicketCache) GetTicketCache(nodeid discover.NodeID) ([]common.Hash, err func (tc TicketCache) RemoveTicketCache(nodeid discover.NodeID, tids []common.Hash) error { cache, ok := tc[nodeid] if !ok { + log.Error("Failed to RemoveTicketCache, the ticketIds is empty !!!!", "nodeId", nodeid.String()) return ErrNotfindFromNodeId } mapTIds := make(map[common.Hash]common.Hash) @@ -294,9 +361,16 @@ func (tc TicketCache) TCount(nodeid discover.NodeID) uint64 { return uint64(len(tc[nodeid])) } +// copy a cache as (nodeId => []ticketId) func (tc TicketCache) TicketCaceheSnapshot() TicketCache { + + // create a new cache ret := NewTicketCache() + + // copy data from origin cache for nodeid, tids := range tc { + + // []ticketId arr := make([]common.Hash, len(tids)) copy(arr, tids) ret[nodeid] = arr diff --git a/core/types/candidate.go b/core/types/candidate.go index d836b5bd21..6566f01d02 100644 --- a/core/types/candidate.go +++ b/core/types/candidate.go @@ -1,9 +1,9 @@ package types import ( - "math/big" - "github.com/PlatONnetwork/PlatON-Go/p2p/discover" "github.com/PlatONnetwork/PlatON-Go/common" + "github.com/PlatONnetwork/PlatON-Go/p2p/discover" + "math/big" ) type CanConditions map[discover.NodeID]*big.Int @@ -12,9 +12,9 @@ type CandidateQueue []*Candidate func compare(cand CanConditions, c, can *Candidate) int { // put the larger deposit in front - if cand[c.CandidateId].Cmp(cand[can.CandidateId]) > 0 /* c.Deposit.Cmp(can.Deposit) > 0*/ { + if cand[c.CandidateId].Cmp(cand[can.CandidateId]) > 0 /* c.Deposit.Cmp(can.Deposit) > 0*/ { return 1 - } else if cand[c.CandidateId].Cmp(cand[can.CandidateId]) == 0 /* c.Deposit.Cmp(can.Deposit) == 0 */{ + } else if cand[c.CandidateId].Cmp(cand[can.CandidateId]) == 0 /* c.Deposit.Cmp(can.Deposit) == 0 */ { // put the smaller blocknumber in front if c.BlockNumber.Cmp(can.BlockNumber) > 0 { return -1 @@ -40,7 +40,7 @@ func (arr CandidateQueue) CandidateSort(cand CanConditions) { if len(arr) <= 1 { return } - arr.quickSort(cand,0, len(arr)-1) + arr.quickSort(cand, 0, len(arr)-1) } func (arr CandidateQueue) quickSort(cand CanConditions, left, right int) { if left < right { @@ -71,31 +71,30 @@ func (arr CandidateQueue) partition(cand CanConditions, left, right int) int { // candiate info type Candidate struct { - // Mortgage amount (margin) - Deposit *big.Int + Deposit *big.Int // Current block height number at the time of the mortgage - BlockNumber *big.Int + BlockNumber *big.Int // Current tx'index at the time of the mortgage - TxIndex uint32 + TxIndex uint32 // candidate's server nodeId - CandidateId discover.NodeID - Host string - Port string + CandidateId discover.NodeID + Host string + Port string // Mortgage beneficiary's account address - Owner common.Address + Owner common.Address // The account address of initiating a mortgaged - From common.Address - Extra string + From common.Address + Extra string // brokerage example: (fee/10000) * 100% == x% - Fee uint64 + Fee uint64 // Selected TicketId - TicketId common.Hash + TicketId common.Hash } type CandidateAttach struct { // Sum Ticket age - Epoch *big.Int `json:"epoch"` + Epoch *big.Int `json:"epoch"` } func (ca *CandidateAttach) AddEpoch(number *big.Int) { @@ -107,4 +106,3 @@ func (ca *CandidateAttach) SubEpoch(number *big.Int) { ca.Epoch.Sub(ca.Epoch, number) } } - diff --git a/core/vc_list.go b/core/vc_list.go index 1d562aa0ab..312a0bc96b 100644 --- a/core/vc_list.go +++ b/core/vc_list.go @@ -1,8 +1,9 @@ package core import ( - "github.com/PlatONnetwork/PlatON-Go/core/types" "container/heap" + + "github.com/PlatONnetwork/PlatON-Go/core/types" ) type vcHeap []*types.TransactionWrap @@ -30,14 +31,14 @@ func (h *vcHeap) Pop() interface{} { } type vcList struct { - all *vcLookup - items *vcHeap - stales int + all *vcLookup + items *vcHeap + stales int } func newVCList(all *vcLookup) *vcList { return &vcList{ - all : all, + all: all, items: new(vcHeap), } } @@ -49,20 +50,3 @@ func (l *vcList) Put(tx *types.TransactionWrap) { func (l *vcList) Pop() *types.TransactionWrap { return heap.Pop(l.items).(*types.TransactionWrap) } - - - - - - - - - - - - - - - - - diff --git a/core/vm/candidate_pool.go b/core/vm/candidate_pool.go index 30d2d15832..215fd39ff8 100644 --- a/core/vm/candidate_pool.go +++ b/core/vm/candidate_pool.go @@ -47,6 +47,7 @@ type candidatePoolContext interface { GetRefundInterval() uint64 MaxCount() uint64 MaxChair() uint64 + GetLuckyTickets(state StateDB, flag int) ([]common.Hash, error) } type CandidateContract struct { @@ -60,7 +61,7 @@ func (c *CandidateContract) RequiredGas(input []byte) uint64 { func (c *CandidateContract) Run(input []byte) ([]byte, error) { if nil == c.Evm.CandidatePoolContext { - log.Error("Failed to Run==> ", "ErrCandidateEmpty: ", ErrCandidatePoolEmpty.Error()) + log.Error("Failed to Run==> ", "ErrCandidatePoolEmpty: ", ErrCandidatePoolEmpty.Error()) return nil, ErrCandidatePoolEmpty } var command = map[string]interface{}{ @@ -73,6 +74,7 @@ func (c *CandidateContract) Run(input []byte) ([]byte, error) { "CandidateWithdrawInfos": c.CandidateWithdrawInfos, "VerifiersList": c.VerifiersList, "GetBatchCandidateDetail": c.GetBatchCandidateDetail, + "GetCurrentRLuckyTickets": c.GetCurrentRLuckyTickets, } return execute(input, command) } @@ -98,7 +100,7 @@ func (c *CandidateContract) CandidateDeposit(nodeId discover.NodeID, owner commo addr := c.Evm.CandidatePoolContext.GetOwner(c.Evm.StateDB, nodeId) if common.ZeroAddr != addr { if ok := bytes.Equal(addr.Bytes(), owner.Bytes()); !ok { - log.Error("Failed to CandidateDeposit==> ", "ErrOwnerNotonly: ", ErrOwnerNotOnly.Error()) + log.Error("Failed to CandidateDeposit==> ", "ErrOwnerNotOnly: ", ErrOwnerNotOnly.Error()) return nil, ErrOwnerNotOnly } } @@ -144,35 +146,35 @@ func (c *CandidateContract) CandidateApplyWithdraw(nodeId discover.NodeID, withd txHash := c.Evm.StateDB.TxHash() from := c.Contract.caller.Address() height := c.Evm.Context.BlockNumber - log.Info("Input to CandidateApplyWithdraw==> ", "nodeId: ", nodeId.String(), " from: ", from.Hex(), " txHash: ", txHash.Hex(), " withdraw: ", withdraw, " height: ", height) + log.Info("Input to CandidateApplyWithdraw on WithdrawCandidate==> ", "nodeId: ", nodeId.String(), " from: ", from.Hex(), " txHash: ", txHash.Hex(), " withdraw: ", withdraw, " height: ", height) can, err := c.Evm.CandidatePoolContext.GetCandidate(c.Evm.StateDB, nodeId) if nil != err { - log.Error("Failed to CandidateApplyWithdraw==> ", "GetCandidate return err: ", err.Error()) + log.Error("Failed to CandidateApplyWithdraw on WithdrawCandidate==> ", "GetCandidate return err: ", err.Error()) return nil, err } if nil == can { - log.Error("Failed to CandidateApplyWithdraw==> ", "ErrCandidateNotExist: ", ErrCandidateNotExist.Error()) + log.Error("Failed to CandidateApplyWithdraw on WithdrawCandidate==> ", "ErrCandidateNotExist: ", ErrCandidateNotExist.Error()) return nil, ErrCandidateNotExist } if can.Deposit.Cmp(big.NewInt(0)) < 1 { - log.Error("Failed to CandidateApplyWithdraw==> ", "ErrWithdrawEmpty: ", ErrWithdrawEmpty.Error()) + log.Error("Failed to CandidateApplyWithdraw on WithdrawCandidate==> ", "ErrWithdrawEmpty: ", ErrWithdrawEmpty.Error()) return nil, ErrWithdrawEmpty } if ok := bytes.Equal(can.Owner.Bytes(), from.Bytes()); !ok { - log.Error("Failed to CandidateApplyWithdraw==> ", "ErrPermissionDenied: ", ErrPermissionDenied.Error()) + log.Error("Failed to CandidateApplyWithdraw on WithdrawCandidate==> ", "ErrPermissionDenied: ", ErrPermissionDenied.Error()) return nil, ErrPermissionDenied } if withdraw.Cmp(can.Deposit) > 0 { withdraw = can.Deposit } if err := c.Evm.CandidatePoolContext.WithdrawCandidate(c.Evm.StateDB, nodeId, withdraw, height); nil != err { - log.Error("Failed to CandidateApplyWithdraw==> ", "WithdrawCandidate return err: ", err.Error()) + log.Error("Failed to CandidateApplyWithdraw on WithdrawCandidate==> ", "WithdrawCandidate return err: ", err.Error()) return nil, err } r := ResultCommon{true, "", "success"} event, _ := json.Marshal(r) c.addLog(CandidateApplyWithdrawEvent, string(event)) - log.Info("Result of CandidateApplyWithdraw==> ", "json: ", string(event)) + log.Info("Result of CandidateApplyWithdraw on WithdrawCandidate==> ", "json: ", string(event)) return nil, nil } @@ -180,15 +182,15 @@ func (c *CandidateContract) CandidateApplyWithdraw(nodeId discover.NodeID, withd func (c *CandidateContract) CandidateWithdraw(nodeId discover.NodeID) ([]byte, error) { txHash := c.Evm.StateDB.TxHash() height := c.Evm.Context.BlockNumber - log.Info("Input to CandidateWithdraw==> ", "nodeId: ", nodeId.String(), " height: ", height, " txHash: ", txHash.Hex()) + log.Info("Input to CandidateWithdraw to RefundBalance==> ", "nodeId: ", nodeId.String(), " height: ", height, " txHash: ", txHash.Hex()) if err := c.Evm.CandidatePoolContext.RefundBalance(c.Evm.StateDB, nodeId, height); nil != err { - log.Error("Failed to CandidateWithdraw==> ", "RefundBalance return err: ", err.Error()) + log.Error("Failed to CandidateWithdraw to RefundBalance==> ", "RefundBalance return err: ", err.Error()) return nil, err } r := ResultCommon{true, "", "success"} event, _ := json.Marshal(r) c.addLog(CandidateWithdrawEvent, string(event)) - log.Info("Result of CandidateWithdraw==> ", "json: ", string(event)) + log.Info("Result of CandidateWithdraw to RefundBalance==> ", "json: ", string(event)) return nil, nil } @@ -324,6 +326,18 @@ func (c *CandidateContract) VerifiersList() ([]byte, error) { return sdata, nil } +// GetCurrentRLuckyTickets return the current round's lucky ticketIds. +func (c *CandidateContract) GetCurrentRLuckyTickets() ([]byte, error) { + ticketIds, err := c.Evm.CandidatePoolContext.GetLuckyTickets(c.Evm.StateDB, 0) + if nil != err { + log.Error("Failed to GetCurrentRLuckyTickets==> ", "GetLuckyTickets return err: ", err.Error()) + } + data, _ := json.Marshal(ticketIds) + sdata := DecodeResultStr(string(data)) + log.Info("Result of GetCurrentRLuckyTickets==> ", "len(ticketIds): ", len(ticketIds), "json: ", string(data)) + return sdata, nil +} + // addLog let the result add to event. func (c *CandidateContract) addLog(event, data string) { var logdata [][]byte diff --git a/core/vm/candidate_pool_test.go b/core/vm/candidate_pool_test.go index 80e10b59df..71028e0d05 100644 --- a/core/vm/candidate_pool_test.go +++ b/core/vm/candidate_pool_test.go @@ -116,7 +116,7 @@ func newChainState() (*state.StateDB, error) { return state, nil } -func newPool() (*pposm.CandidatePoolContext, *pposm.TicketPool) { +func newPool() (*pposm.CandidatePoolContext, *pposm.TicketPoolContext) { configs := ¶ms.PposConfig{ CandidateConfig: ¶ms.CandidateConfig{ Threshold: "100", @@ -131,16 +131,16 @@ func newPool() (*pposm.CandidatePoolContext, *pposm.TicketPool) { ExpireBlockNumber: 100, }, } - return pposm.NewCandidatePoolContext(configs), pposm.NewTicketPool(configs) + return pposm.NewCandidatePoolContext(configs), pposm.NewTicketPoolContext(configs) } func newEvm() *vm.EVM { state, _ := newChainState() - candidatePoolContext, ticketPool := newPool() + candidatePoolContext, ticketPoolContext := newPool() evm := &vm.EVM{ StateDB: state, CandidatePoolContext: candidatePoolContext, - TicketPool: ticketPool, + TicketPoolContext: ticketPoolContext, } context := vm.Context{ BlockNumber: big.NewInt(7), @@ -610,6 +610,20 @@ func TestCandidatePoolEncode(t *testing.T) { } else { fmt.Println("VerifiersList data rlp: ", hexutil.Encode(bufVerifiersList.Bytes())) } + + // GetCurrentRLuckyTickets() + var GetCurrentRLuckyTickets [][]byte + GetCurrentRLuckyTickets = make([][]byte, 0) + GetCurrentRLuckyTickets = append(GetCurrentRLuckyTickets, uint64ToBytes(0xf1)) + GetCurrentRLuckyTickets = append(GetCurrentRLuckyTickets, []byte("GetCurrentRLuckyTickets")) + bufGetCurrentRLuckyTickets := new(bytes.Buffer) + err = rlp.Encode(bufGetCurrentRLuckyTickets, GetCurrentRLuckyTickets) + if err != nil { + fmt.Println(err) + t.Errorf("GetCurrentRLuckyTickets encode rlp data fail") + } else { + fmt.Println("GetCurrentRLuckyTickets data rlp: ", hexutil.Encode(bufGetCurrentRLuckyTickets.Bytes())) + } } func TestCandidatePoolDecode(t *testing.T) { diff --git a/core/vm/evm.go b/core/vm/evm.go index cbca559ff1..6b20f5a216 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -54,18 +54,21 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err } // ppos if p := PrecompiledContractsPpos[*contract.CodeAddr]; p != nil { - - if c, ok := p.(*CandidateContract); ok { - c.Contract = contract - c.Evm = evm - } - if t, ok := p.(*TicketContract); ok { - t.Contract = contract - t.Evm = evm - - } log.Info("IN PPOS PrecompiledContractsPpos ... ") - return RunPrecompiledContract(p, input, contract) + switch r := p.(type) { + case *CandidateContract: + r = &CandidateContract{} + r.Contract = contract + r.Evm = evm + return RunPrecompiledContract(r, input, contract) + case *TicketContract: + r = &TicketContract{} + r.Contract = contract + r.Evm = evm + return RunPrecompiledContract(r, input, contract) + default: + log.Error("error type","contract.CodeAddr",*contract.CodeAddr) + } } } @@ -146,7 +149,7 @@ type EVM struct { //ppos add CandidatePoolContext candidatePoolContext - TicketPool ticketPool + TicketPoolContext ticketPoolContext } // NewEVM returns a new EVM. The returned EVM is not thread safe and should diff --git a/core/vm/interpreter_life.go b/core/vm/interpreter_life.go index 0b582938ea..1c53ff60dd 100644 --- a/core/vm/interpreter_life.go +++ b/core/vm/interpreter_life.go @@ -13,6 +13,7 @@ import ( "github.com/PlatONnetwork/PlatON-Go/rlp" "math/big" "reflect" + "runtime" "strings" "github.com/PlatONnetwork/PlatON-Go/life/exec" @@ -71,6 +72,7 @@ func NewWASMInterpreter(evm *EVM, cfg Config) *WASMInterpreter { func (in *WASMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { defer func() { if er := recover(); er != nil { + fmt.Println(stack()) ret, err = nil, fmt.Errorf("VM execute fail: %v", er) } }() @@ -341,3 +343,8 @@ func parseRlpData(rlpData []byte) (int64, []byte, []byte, error) { } return txType, abi, code, nil } + +func stack() string { + var buf [2 << 10]byte + return string(buf[:runtime.Stack(buf[:], true)]) +} diff --git a/core/vm/ppos_precontracts.go b/core/vm/ppos_precontracts.go index 2a47940488..303509a2ad 100644 --- a/core/vm/ppos_precontracts.go +++ b/core/vm/ppos_precontracts.go @@ -9,6 +9,7 @@ import ( "github.com/PlatONnetwork/PlatON-Go/common/byteutil" "github.com/PlatONnetwork/PlatON-Go/log" "github.com/PlatONnetwork/PlatON-Go/rlp" + gerr "github.com/go-errors/errors" "reflect" ) @@ -32,7 +33,8 @@ func execute(input []byte, command map[string]interface{}) ([]byte, error) { defer func() { if err := recover(); nil != err { // catch call panic - log.Error("Failed to execute==> ", "err: ", fmt.Sprint(err)) + msg := fmt.Sprintf("panic: %v\n", gerr.Wrap(err, 2).ErrorStack()) + log.Error("Failed to execute==> ", "err: ", fmt.Sprint(err), "\nstack: ", msg) } }() var source [][]byte diff --git a/core/vm/ticket_pool.go b/core/vm/ticket_pool.go index 451acb247e..57f521e573 100644 --- a/core/vm/ticket_pool.go +++ b/core/vm/ticket_pool.go @@ -25,12 +25,13 @@ const ( VoteTicketEvent = "VoteTicketEvent" ) -type ticketPool interface { +type ticketPoolContext interface { VoteTicket(stateDB StateDB, owner common.Address, voteNumber uint64, deposit *big.Int, nodeId discover.NodeID, blockNumber *big.Int) ([]common.Hash, error) GetTicket(stateDB StateDB, ticketId common.Hash) (*types.Ticket, error) GetTicketList(stateDB StateDB, ticketIds []common.Hash) ([]*types.Ticket, error) GetCandidateTicketIds(stateDB StateDB, nodeId discover.NodeID) ([]common.Hash, error) GetCandidatesTicketIds(stateDB StateDB, nodeIds []discover.NodeID) (map[discover.NodeID][]common.Hash, error) + GetCandidatesTicketCount(stateDB StateDB, nodeIds []discover.NodeID) (map[discover.NodeID]int, error) GetCandidateEpoch(stateDB StateDB, nodeId discover.NodeID) (uint64, error) GetPoolNumber(stateDB StateDB) (uint64, error) GetTicketPrice(stateDB StateDB) (*big.Int, error) @@ -46,19 +47,20 @@ func (t *TicketContract) RequiredGas(input []byte) uint64 { } func (t *TicketContract) Run(input []byte) ([]byte, error) { - if nil == t.Evm.TicketPool { + if nil == t.Evm.TicketPoolContext { log.Error("Failed to Run==> ", "ErrTicketPoolEmpty: ", ErrTicketPoolEmpty.Error()) return nil, ErrTicketPoolEmpty } var command = map[string]interface{}{ - "VoteTicket": t.VoteTicket, - "GetTicketDetail": t.GetTicketDetail, - "GetBatchTicketDetail": t.GetBatchTicketDetail, - "GetCandidateTicketIds": t.GetCandidateTicketIds, - "GetBatchCandidateTicketIds": t.GetBatchCandidateTicketIds, - "GetCandidateEpoch": t.GetCandidateEpoch, - "GetPoolRemainder": t.GetPoolRemainder, - "GetTicketPrice": t.GetTicketPrice, + "VoteTicket": t.VoteTicket, + "GetTicketDetail": t.GetTicketDetail, + "GetBatchTicketDetail": t.GetBatchTicketDetail, + "GetCandidateTicketIds": t.GetCandidateTicketIds, + "GetBatchCandidateTicketIds": t.GetBatchCandidateTicketIds, + "GetBatchCandidateTicketCount": t.GetBatchCandidateTicketCount, + "GetCandidateEpoch": t.GetCandidateEpoch, + "GetPoolRemainder": t.GetPoolRemainder, + "GetTicketPrice": t.GetTicketPrice, } return execute(input, command) } @@ -72,7 +74,7 @@ func (t *TicketContract) VoteTicket(count uint64, price *big.Int, nodeId discove from := t.Contract.caller.Address() log.Info("Input to VoteTicket==>", " nodeId: ", nodeId.String(), " owner: ", from.Hex(), " txhash: ", txHash.Hex(), " txIdx: ", txIdx, " blockNumber: ", blockNumber, " value: ", value, " count: ", count, " price: ", price) - if ticketPrice, err := t.Evm.TicketPool.GetTicketPrice(t.Evm.StateDB); nil == err { + if ticketPrice, err := t.Evm.TicketPoolContext.GetTicketPrice(t.Evm.StateDB); nil == err { if price.Cmp(ticketPrice) < 0 { log.Error("Failed to VoteTicket==> ", "ErrTicketPrice: ", ErrTicketPrice.Error()) return nil, ErrTicketPrice @@ -95,12 +97,12 @@ func (t *TicketContract) VoteTicket(count uint64, price *big.Int, nodeId discove log.Error("Failed to VoteTicket==> ", "ErrCandidateNotExist: ", ErrCandidateNotExist.Error()) return nil, ErrCandidateNotExist } - ticketIds, err := t.Evm.TicketPool.VoteTicket(t.Evm.StateDB, from, count, price, nodeId, blockNumber) - if nil == ticketIds { - log.Error("Failed to VoteTicket==> ", "VoteTicket return err(nil == ticketIds): ", err.Error()) + ticketIds, err := t.Evm.TicketPoolContext.VoteTicket(t.Evm.StateDB, from, count, price, nodeId, blockNumber) + data := len(ticketIds) + if 0 == data { + log.Error("Failed to VoteTicket==> ", "VoteTicket return err(0 == len(ticketIds)): ", err.Error()) return nil, err } - data := len(ticketIds) // return the extra money if uint64(data) < count { failNum := count - uint64(data) @@ -111,7 +113,7 @@ func (t *TicketContract) VoteTicket(count uint64, price *big.Int, nodeId discove sdata := DecodeResultStr(strconv.Itoa(data)) log.Info("Result of VoteTicket==> ", "len(successTicketIds): ", strconv.Itoa(data), " []byte: ", sdata) if nil != err { - log.Error("Failed to VoteTicket==> ", "VoteTicket return err: ", err.Error()) + log.Warn("Failed to VoteTicket==> ", "VoteTicket return err: ", err.Error()) r := ResultCommon{true, strconv.Itoa(data), err.Error()} event, _ := json.Marshal(r) t.addLog(VoteTicketEvent, string(event)) @@ -126,7 +128,7 @@ func (t *TicketContract) VoteTicket(count uint64, price *big.Int, nodeId discove // GetTicketDetail returns the ticket info. func (t *TicketContract) GetTicketDetail(ticketId common.Hash) ([]byte, error) { log.Info("Input to GetTicketDetail==> ", "ticketId: ", ticketId.Hex()) - ticket, err := t.Evm.TicketPool.GetTicket(t.Evm.StateDB, ticketId) + ticket, err := t.Evm.TicketPoolContext.GetTicket(t.Evm.StateDB, ticketId) if nil != err { log.Error("Failed to GetTicketDetail==> ", "GetTicket return err: ", err.Error()) ticket := types.Ticket{} @@ -144,7 +146,7 @@ func (t *TicketContract) GetTicketDetail(ticketId common.Hash) ([]byte, error) { func (t *TicketContract) GetBatchTicketDetail(ticketIds []common.Hash) ([]byte, error) { input, _ := json.Marshal(ticketIds) log.Info("Input to GetBatchTicketDetail==>", "length: ", len(ticketIds), "ticketIds: ", string(input)) - tickets, _ := t.Evm.TicketPool.GetTicketList(t.Evm.StateDB, ticketIds) + tickets, _ := t.Evm.TicketPoolContext.GetTicketList(t.Evm.StateDB, ticketIds) if 0 == len(tickets) { log.Warn("Failed to GetBatchTicketDetail==> The query does not exist") tickets := make([]types.Ticket, 0) @@ -161,7 +163,7 @@ func (t *TicketContract) GetBatchTicketDetail(ticketIds []common.Hash) ([]byte, // GetCandidateTicketIds returns the list of ticketId for the candidate. func (t *TicketContract) GetCandidateTicketIds(nodeId discover.NodeID) ([]byte, error) { log.Info("Input to GetCandidateTicketIds==> ", " nodeId: ", nodeId.String()) - candidateTicketIds, err := t.Evm.TicketPool.GetCandidateTicketIds(t.Evm.StateDB, nodeId) + candidateTicketIds, err := t.Evm.TicketPoolContext.GetCandidateTicketIds(t.Evm.StateDB, nodeId) if nil != err { log.Warn("Failed to GetCandidateTicketIds==> ", "GetCandidateTicketIds return err: ", err.Error()) candidateTicketIds := make([]common.Hash, 0) @@ -179,7 +181,7 @@ func (t *TicketContract) GetCandidateTicketIds(nodeId discover.NodeID) ([]byte, func (t *TicketContract) GetBatchCandidateTicketIds(nodeIds []discover.NodeID) ([]byte, error) { input, _ := json.Marshal(nodeIds) log.Info("Input to GetBatchCandidateTicketIds==> ", "length: ", len(nodeIds), "nodeIds: ", string(input)) - candidatesTicketIds, _ := t.Evm.TicketPool.GetCandidatesTicketIds(t.Evm.StateDB, nodeIds) + candidatesTicketIds, _ := t.Evm.TicketPoolContext.GetCandidatesTicketIds(t.Evm.StateDB, nodeIds) if 0 == len(candidatesTicketIds) { log.Warn("Failed to GetBatchCandidateTicketIds==> The query does not exist") candidatesTicketIds := make(map[discover.NodeID][]common.Hash, 0) @@ -193,10 +195,28 @@ func (t *TicketContract) GetBatchCandidateTicketIds(nodeIds []discover.NodeID) ( return sdata, nil } +// GetBatchCandidateTicketCount returns the number of candidate's ticket. +func (t *TicketContract) GetBatchCandidateTicketCount(nodeIds []discover.NodeID) ([]byte, error) { + input, _ := json.Marshal(nodeIds) + log.Info("Input to GetBatchCandidateTicketCount==> ", "length: ", len(nodeIds), "nodeIds: ", string(input)) + candidatesTicketCount, _ := t.Evm.TicketPoolContext.GetCandidatesTicketCount(t.Evm.StateDB, nodeIds) + if 0 == len(candidatesTicketCount) { + log.Warn("Failed to GetBatchCandidateTicketCount==> The query does not exist") + candidatesTicketCount := make(map[discover.NodeID]int, 0) + data, _ := json.Marshal(candidatesTicketCount) + sdata := DecodeResultStr(string(data)) + return sdata, nil + } + data, _ := json.Marshal(candidatesTicketCount) + sdata := DecodeResultStr(string(data)) + log.Info("Result of GetBatchCandidateTicketCount==> ", "len(candidatesTicketCount): ", len(candidatesTicketCount), "json: ", string(data)) + return sdata, nil +} + // GetEpoch returns the current ticket age for the candidate. func (t *TicketContract) GetCandidateEpoch(nodeId discover.NodeID) ([]byte, error) { log.Info("Input to GetCandidateEpoch==> ", " nodeId: ", nodeId.String()) - epoch, err := t.Evm.TicketPool.GetCandidateEpoch(t.Evm.StateDB, nodeId) + epoch, err := t.Evm.TicketPoolContext.GetCandidateEpoch(t.Evm.StateDB, nodeId) if nil != err { log.Error("Failed to GetCandidateEpoch==> ", "GetCandidateEpoch return err: ", err.Error()) data, _ := json.Marshal(epoch) @@ -211,7 +231,7 @@ func (t *TicketContract) GetCandidateEpoch(nodeId discover.NodeID) ([]byte, erro // GetPoolRemainder returns the amount of remaining tickets in the ticket pool. func (t *TicketContract) GetPoolRemainder() ([]byte, error) { - remainder, err := t.Evm.TicketPool.GetPoolNumber(t.Evm.StateDB) + remainder, err := t.Evm.TicketPoolContext.GetPoolNumber(t.Evm.StateDB) if nil != err { log.Error("Failed to GetPoolRemainder==> ", "GetPoolNumber return err: ", err.Error()) data, _ := json.Marshal(remainder) @@ -226,7 +246,7 @@ func (t *TicketContract) GetPoolRemainder() ([]byte, error) { // GetTicketPrice returns the current ticket price for the ticket pool. func (t *TicketContract) GetTicketPrice() ([]byte, error) { - price, err := t.Evm.TicketPool.GetTicketPrice(t.Evm.StateDB) + price, err := t.Evm.TicketPoolContext.GetTicketPrice(t.Evm.StateDB) if nil != err { log.Error("Failed to GetTicketPrice==> ", "GetTicketPrice return err: ", err.Error()) data, _ := json.Marshal(price) diff --git a/core/vm/ticket_pool_test.go b/core/vm/ticket_pool_test.go index f31261df50..67a9c60349 100644 --- a/core/vm/ticket_pool_test.go +++ b/core/vm/ticket_pool_test.go @@ -339,6 +339,92 @@ func TestGetBatchCandidateTicketIds(t *testing.T) { fmt.Println("The candidate's ticketId are: ", vm.ResultByte2Json(resByte)) } +func TestGetBatchCandidateTicketCount(t *testing.T) { + contract := newContract() + evm := newEvm() + + ticketContract := vm.TicketContract{ + contract, + evm, + } + candidateContract := vm.CandidateContract{ + contract, + evm, + } + nodeId1 := discover.MustHexID("0x01234567890121345678901123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345") + owner := common.HexToAddress("0x12") + fee := uint64(7000) + host := "192.168.9.184" + port := "16789" + extra := "{\"nodeName\": \"Platon-Beijing\", \"nodePortrait\": \"\",\"nodeDiscription\": \"PlatON-Gravitational area\",\"nodeDepartment\": \"JUZIX\",\"officialWebsite\": \"https://www.platon.network/\",\"time\":1546503651190}" + fmt.Println("CandidateDeposit input==>", "nodeId1: ", nodeId1.String(), "owner: ", owner.Hex(), "fee: ", fee, "host: ", host, "port: ", port, "extra: ", extra) + _, err := candidateContract.CandidateDeposit(nodeId1, owner, fee, host, port, extra) + if nil != err { + fmt.Println("CandidateDeposit fail", "err", err) + } + fmt.Println("CandidateDeposit1 success") + + nodeId2 := discover.MustHexID("0x11234567890121345678901123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345") + owner = common.HexToAddress("0x12") + fee = uint64(8000) + host = "192.168.9.185" + port = "16789" + extra = "{\"nodeName\": \"Platon-Shenzhen\", \"nodePortrait\": \"\",\"nodeDiscription\": \"PlatON-Cosmic wave\",\"nodeDepartment\": \"JUZIX\",\"officialWebsite\": \"https://www.platon.network/sz\",\"time\":1546503651190}" + fmt.Println("CandidateDeposit input==>", "nodeId2: ", nodeId2.String(), "owner: ", owner.Hex(), "fee: ", fee, "host: ", host, "port: ", port, "extra: ", extra) + _, err = candidateContract.CandidateDeposit(nodeId2, owner, fee, host, port, extra) + if nil != err { + fmt.Println("CandidateDeposit fail", "err", err) + } + fmt.Println("CandidateDeposit2 success") + + // CandidateList() ([]byte, error) + resByte, err := candidateContract.CandidateList() + if nil != err { + fmt.Println("CandidateList fail", "err", err) + } + if nil == resByte { + fmt.Println("The candidate list is null") + return + } + fmt.Println("The candidate list is: ", vm.ResultByte2Json(resByte)) + + // Vote to Candidate1 + count := uint64(100) + price := big.NewInt(1) + fmt.Println("VoteTicket input==>", "count: ", count, "price: ", price, "nodeId1: ", nodeId1.String()) + resByte, err = ticketContract.VoteTicket(count, price, nodeId1) + if nil != err { + fmt.Println("VoteTicket fail", "err", err) + } + fmt.Println("The list of generated ticketId is: ", vm.ResultByte2Json(resByte)) + + // Vote to Candidate2 + count = uint64(101) + price = big.NewInt(1) + fmt.Println("VoteTicket input==>", "count: ", count, "price: ", price, "nodeId2: ", nodeId2.String()) + resByte, err = ticketContract.VoteTicket(count, price, nodeId2) + if nil != err { + fmt.Println("VoteTicket fail", "err", err) + } + fmt.Println("The list of generated ticketId is: ", vm.ResultByte2Json(resByte)) + + // GetBatchCandidateTicketCount(nodeIds []discover.NodeID) ([]byte, error) + fmt.Println("GetBatchCandidateTicketCount input==>", "nodeIds: ", nodeId1.String(), nodeId2.String()) + var nodeIds []discover.NodeID + nodeId1 = discover.MustHexID("0x01234567890121345678901123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345") + nodeId2 = discover.MustHexID("0x11234567890121345678901123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345") + nodeIds = append(append(nodeIds, nodeId1), nodeId2) + resByte, err = ticketContract.GetBatchCandidateTicketCount(nodeIds) + if nil != err { + fmt.Println("GetBatchCandidateTicketCount fail", "err", err) + } + if nil == resByte { + fmt.Println("The candidates's ticket list is null") + return + } + fmt.Println("The number of candidate's ticket is: ", vm.ResultByte2Json(resByte)) +} + func TestGetCandidateEpoch(t *testing.T) { contract := newContract() evm := newEvm() diff --git a/eth/config.go b/eth/config.go index d6f0ede379..16deb83d44 100644 --- a/eth/config.go +++ b/eth/config.go @@ -52,13 +52,13 @@ var DefaultConfig = Config{ Candidate: &CandidateConfig{ Threshold: "1000000000000000000000000", DepositLimit: 10, - Allowed: 100, + Allowed: 512, MaxChair: 10, MaxCount: 100, RefundBlockNumber: 512, }, Ticket: &TicketConfig{ - TicketPrice: "1000000000000000000", + TicketPrice: "100000000000000000000", MaxCount: 51200, ExpireBlockNumber: 1536000, }, diff --git a/eth/handler.go b/eth/handler.go index 816a1b0ac4..123a07b16b 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -640,7 +640,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { // Mark the hashes as present at the remote node for _, block := range announces { p.MarkBlock(block.Hash) - log.Debug("Received a message[NewBlockHashesMsg]------------", "GoRoutineID", common.CurrentGoRoutineID(), "receiveAt", msg.ReceivedAt.Unix(), "peerId", p.id, "hash", block.Hash, "number", block.Number) + log.Debug("Received a message[NewBlockHashesMsg]", "GoRoutineID", common.CurrentGoRoutineID(), "receiveAt", msg.ReceivedAt.Unix(), "peerId", p.id, "hash", block.Hash, "number", block.Number) } // Schedule all the unknown hashes for retrieval unknown := make(newBlockHashesData, 0, len(announces)) @@ -662,7 +662,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { request.Block.ReceivedAt = msg.ReceivedAt request.Block.ReceivedFrom = p - log.Debug("Received a message[NewBlockMsg]------------", "GoRoutineID", common.CurrentGoRoutineID(), "receiveAt", request.Block.ReceivedAt.Unix(), "peerId", p.id, "hash", request.Block.Hash(), "number", request.Block.NumberU64()) + log.Debug("Received a message[NewBlockMsg]", "GoRoutineID", common.CurrentGoRoutineID(), "receiveAt", request.Block.ReceivedAt.Unix(), "peerId", p.id, "hash", request.Block.Hash(), "number", request.Block.NumberU64()) // Mark the peer as owning the block and schedule it for import p.MarkBlock(request.Block.Hash()) @@ -714,7 +714,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { if err := msg.Decode(&request); err != nil { return errResp(ErrDecode, "%v: %v", msg, err) } - log.Warn("Received a broadcast message[PrepareBlockMsg]------------", "GoRoutineID", common.CurrentGoRoutineID(), "peerId", p.id, "hash", request.Block.Hash(), "number", request.Block.NumberU64()) + log.Debug("Received a broadcast message[PrepareBlockMsg]", "GoRoutineID", common.CurrentGoRoutineID(), "peerId", p.id, "hash", request.Block.Hash(), "number", request.Block.NumberU64()) request.Block.ReceivedAt = msg.ReceivedAt request.Block.ReceivedFrom = p @@ -756,7 +756,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "%v: %v", msg, err) } - log.Warn("------------Received a broadcast message[BlockSignatureMsg]------------", "GoRoutineID", common.CurrentGoRoutineID(), "peerId", p.id, "SignHash", request.SignHash, "Hash", request.Hash, "Number", request.Number, "Signature", request.Signature.String()) + log.Debug("Received a broadcast message[BlockSignatureMsg]", "GoRoutineID", common.CurrentGoRoutineID(), "peerId", p.id, "SignHash", request.SignHash, "Hash", request.Hash, "Number", request.Number, "Signature", request.Signature.String()) engineBlockSignature := &cbfttypes.BlockSignature{SignHash: request.SignHash, Hash: request.Hash, Number: request.Number, Signature: request.Signature} if cbftEngine, ok := pm.engine.(consensus.Bft); ok { @@ -791,7 +791,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { for { e := p.PingList.Front() if e != nil { - log.Trace("Front element of p.PingList", "element", e) + log.Debug("Front element of p.PingList", "element", e) if t, ok := p.PingList.Remove(e).(string); ok { if t == pingTime[0] { @@ -800,14 +800,14 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "%v: %v", msg, err) } - log.Trace("calculate net latency", "sendPingTime", tInt64, "receivePongTime", curTime) + log.Debug("calculate net latency", "sendPingTime", tInt64, "receivePongTime", curTime) latency := (curTime - tInt64) / 2 / 1000000 cbftEngine.OnPong(p.Peer.ID(), latency) break } } } else { - log.Trace("end of p.PingList") + log.Debug("end of p.PingList") break } } @@ -864,13 +864,13 @@ func (pm *ProtocolManager) MulticastConsensus(a interface{}, consensusNodes []di if block, ok := a.(*types.Block); ok { for _, peer := range peers { - log.Warn("------------Send a broadcast message[PrepareBlockMsg]------------", + log.Debug("Send a broadcast message[PrepareBlockMsg]", "peerId", peer.id, "Hash", block.Hash(), "Number", block.Number()) peer.AsyncSendPrepareBlock(block) } } else if signature, ok := a.(*cbfttypes.BlockSignature); ok { for _, peer := range peers { - log.Warn("------------Send a broadcast message[BlockSignatureMsg]------------", + log.Debug("Send a broadcast message[BlockSignatureMsg]", "peerId", peer.id, "SignHash", signature.SignHash, "Hash", signature.Hash, "Number", signature.Number, "SignHash", signature.SignHash) peer.AsyncSendSignature(signature) } diff --git a/log/logger.go b/log/logger.go index ca3e0b0599..482eb6eb19 100644 --- a/log/logger.go +++ b/log/logger.go @@ -6,6 +6,7 @@ import ( "time" "github.com/go-stack/stack" + "github.com/PlatONnetwork/PlatON-Go/common" ) const timeKey = "t" @@ -134,7 +135,7 @@ func (l *logger) write(msg string, lvl Lvl, ctx []interface{}, skip int) { l.h.Log(&Record{ Time: time.Now(), Lvl: lvl, - Msg: msg, + Msg: fmt.Sprintf("routine %s ", common.CurrentGoRoutineID()) + msg, Ctx: newContext(l.ctx, ctx), Call: stack.Caller(skip), KeyNames: RecordKeyNames{ diff --git a/miner/worker.go b/miner/worker.go index 17fd4379b4..ef3e3bc842 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -17,10 +17,10 @@ package miner import ( - "github.com/PlatONnetwork/PlatON-Go/consensus/cbft" - "github.com/PlatONnetwork/PlatON-Go/p2p/discover" "bytes" "errors" + "github.com/PlatONnetwork/PlatON-Go/consensus/cbft" + "github.com/PlatONnetwork/PlatON-Go/p2p/discover" "math/big" "sync" "sync/atomic" @@ -95,18 +95,18 @@ type environment struct { tcount int // tx count in cycle gasPool *core.GasPool // available gas used to pack transactions - header *types.Header - txs []*types.Transaction - receipts []*types.Receipt + header *types.Header + txs []*types.Transaction + receipts []*types.Receipt consensusNodes []discover.NodeID } // task contains all information for consensus engine sealing and result submitting. type task struct { - receipts []*types.Receipt - state *state.StateDB - block *types.Block - createdAt time.Time + receipts []*types.Receipt + state *state.StateDB + block *types.Block + createdAt time.Time consensusNodes []discover.NodeID } @@ -118,9 +118,9 @@ const ( // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. type newWorkReq struct { - interrupt *int32 - noempty bool - timestamp int64 + interrupt *int32 + noempty bool + timestamp int64 commitBlock *types.Block } @@ -200,11 +200,11 @@ type worker struct { // External functions isLocalBlock func(block *types.Block) bool // Function used to determine whether the specified block is mined by local miner. - blockChainCache *core.BlockChainCache - commitWorkEnv *commitWorkEnv - recommit time.Duration - commitDuration int64 //in Millisecond - addConsensusPeerFn addConsensusPeerFn + blockChainCache *core.BlockChainCache + commitWorkEnv *commitWorkEnv + recommit time.Duration + commitDuration int64 //in Millisecond + addConsensusPeerFn addConsensusPeerFn // Test hooks newTaskHook func(*task) // Method to call upon receiving a new sealing task. @@ -443,10 +443,10 @@ func (w *worker) newWorkLoop(recommit time.Duration) { // If mining is running resubmit a new work cycle periodically to pull in // higher priced transactions. Disable this overhead for pending blocks. if w.isRunning() { - log.Debug("----------Interval " + recommit.String() + ",attempt to commitNewWork----------") - if _,ok := w.engine.(consensus.Bft); ok { + log.Debug("Interval " + recommit.String() + ",attempt to commitNewWork") + if _, ok := w.engine.(consensus.Bft); ok { if shouldCommit, commitBlock := w.shouldCommit(time.Now().UnixNano() / 1e6); shouldCommit { - log.Debug("--------------node inTurn,Packing Start--------------") + log.Debug("node inTurn,Packing Start", "baseBlockNumber", commitBlock.NumberU64(), "baseBlockHash", commitBlock.Hash()) timestamp = time.Now().UnixNano() / 1e6 commit(false, commitInterruptResubmit, commitBlock) continue @@ -618,7 +618,7 @@ func (w *worker) mainLoop() { } // Broadcast the block and announce chain insertion event - log.Debug("Post PrepareMinedBlockEvent", "consensusNodes", task.consensusNodes) + log.Debug("Post PrepareMinedBlockEvent", "blockNumber", block.NumberU64(), "blockHash", block.Hash(), "consensusNodes", task.consensusNodes) w.mux.Post(core.PrepareMinedBlockEvent{Block: block, ConsensusNodes: task.consensusNodes}) case blockSignature := <-w.blockSignatureCh: @@ -678,6 +678,7 @@ func (w *worker) taskLoop() { // Save stateDB, receipts to blockChainCache w.blockChainCache.WriteStateDB(sealHash, task.state, task.block.NumberU64()) w.blockChainCache.WriteReceipts(sealHash, task.receipts, task.block.NumberU64()) + //w.blockChainCache.MarkBlockHash(task.block.Hash()) if err := cbftEngine.Seal(w.chain, task.block, w.prepareResultCh, stopCh); err != nil { log.Warn("【Bft engine】Block sealing failed", "err", err) } @@ -876,7 +877,7 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error { } // TODO - w.forEachStorage(state, "【makeCurrent】When new the current stateDB instance:") + //w.forEachStorage(state, "【makeCurrent】When new the current stateDB instance:") env := &environment{ signer: types.NewEIP155Signer(w.config.ChainID), @@ -1162,11 +1163,11 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin w.current.state.Prepare(tx.Hash(), common.Hash{}, w.current.tcount) log.Debug("commit transaction", "hash", tx.Hash(), "sender", from, "nonce", tx.Nonce()) - root := w.current.state.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) + root := w.current.state.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) log.Debug("【The Consensus packaging】Before executing the transaction", "blockNumber", w.current.header.Number.Uint64(), "block.root", w.current.header.Root.Hex(), "Real-time state.root", root.Hex()) logs, err := w.commitTransaction(tx, coinbase) - root = w.current.state.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) + root = w.current.state.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) log.Debug("【The Consensus packaging】After executing the transaction", "blockNumber", w.current.header.Number.Uint64(), "block.root", w.current.header.Root.Hex(), "Real-time state.root", root.Hex()) switch err { @@ -1324,7 +1325,7 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64, // execution finished. if _, ok := w.engine.(consensus.Bft); !ok { // TODO - w.forEachStorage(w.current.state, "【The Consensus packaging】,Before executing the transaction") + //w.forEachStorage(w.current.state, "【The Consensus packaging】,Before executing the transaction") w.commit(uncles, nil, false, tstart, nil) } } @@ -1344,7 +1345,7 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64, if len(pending) == 0 { if _, ok := w.engine.(consensus.Bft); ok { // TODO - w.forEachStorage(w.current.state, "【The Consensus packaging】,Before executing the transaction") + //w.forEachStorage(w.current.state, "【The Consensus packaging】,Before executing the transaction") w.commit(uncles, nil, true, tstart, header) } else { w.updateSnapshot() @@ -1367,10 +1368,10 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64, // TODO log.Debug("execute pending transactions", "hash", commitBlock.Hash(), "number", commitBlock.NumberU64(), "localTxCount", len(localTxs), "remoteTxCount", len(remoteTxs), "txsCount", txsCount) - root := w.current.state.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) + root := w.current.state.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) log.Debug("【The Consensus packaging】 commitTransactionsWithHeader Before executing the transaction", "blockNumber", w.current.header.Number.Uint64(), "block.root", w.current.header.Root.Hex(), "Real-time state.root", root.Hex()) - w.forEachStorage(w.current.state, "【The Consensus packaging】,Before executing the transaction") + //w.forEachStorage(w.current.state, "【The Consensus packaging】,Before executing the transaction") startTime = time.Now() var localTimeout = false @@ -1410,9 +1411,9 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st } s := w.current.state.Copy() - root := s.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) - log.Debug("【The Consensus packaging】After executing the transaction, Before call the notify series func", "blockNumber",header.Number.Uint64(), "block.root", header.Root.Hex(), "Real-time state.root", root.Hex()) - w.forEachStorage(w.current.state, "【The Consensus packaging】,After executing the transaction,Before call the notify series func") + root := s.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) + log.Debug("【The Consensus packaging】After executing the transaction, Before call the notify series func", "blockNumber", header.Number.Uint64(), "block.root", header.Root.Hex(), "Real-time state.root", root.Hex()) + //w.forEachStorage(w.current.state, "【The Consensus packaging】,After executing the transaction,Before call the notify series func") if header != nil { if err := w.notify(s, header.Number); err != nil { @@ -1426,25 +1427,24 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st if switchWitnessErr := w.switchWitness(s, header.Number); switchWitnessErr != nil { return errors.New("switchWitness failure") } - w.forEachStorage(s, "【The Consensus packaging】After Election, before call storeHash") + //w.forEachStorage(s, "【The Consensus packaging】After Election, before call storeHash") // ppos Store Hash w.storeHash(s) - w.forEachStorage(s, "【The Consensus packaging】After Election, before tweaking storeHash,before call finalize") + //w.forEachStorage(s, "【The Consensus packaging】After Election, before tweaking storeHash,before call finalize") } //root, _ = s.Commit(w.config.IsEIP158(w.current.header.Number)) //log.Warn("【The Consensus packaging】: Commit", "blockNumber", header.Number.String(), "State.root", root.String()) - root = s.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) - log.Debug("【The Consensus packaging】After executing the transaction, after call the notify series func, before finalize", "blockNumber",header.Number.Uint64(), "block.root", header.Root.Hex(), "Real-time state.root", root.Hex()) - w.forEachStorage(s, "【The Consensus packaging】After executing the transaction, after call the notify series func, before finalize") + root = s.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) + log.Debug("【The Consensus packaging】After executing the transaction, after call the notify series func, before finalize", "blockNumber", header.Number.Uint64(), "block.root", header.Root.Hex(), "Real-time state.root", root.Hex()) + //w.forEachStorage(s, "【The Consensus packaging】After executing the transaction, after call the notify series func, before finalize") block, err := w.engine.Finalize(w.chain, w.current.header, s, w.current.txs, uncles, w.current.receipts) - root = s.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) - log.Debug("【The Consensus packaging】After call finalize", "blockNumber",header.Number.Uint64(), "block.root", header.Root.Hex(), "Real-time state.root", root.Hex()) - w.forEachStorage(s, "【The Consensus packaging】After call finalize") - + root = s.IntermediateRoot(w.config.IsEIP158(w.current.header.Number)) + log.Debug("【The Consensus packaging】After call finalize", "blockNumber", header.Number.Uint64(), "block.root", header.Root.Hex(), "Real-time state.root", root.Hex()) + //w.forEachStorage(s, "【The Consensus packaging】After call finalize") if err != nil { return err @@ -1515,7 +1515,7 @@ func (w *worker) shouldCommit(timestamp int64) (bool, *types.Block) { shouldCommit := baseBlock == nil || baseBlock.Hash() != highestLogicalBlock.Hash() if shouldCommit && timestamp != 0 { - shouldCommit = shouldCommit && (timestamp - commitTime >= w.recommit.Nanoseconds() / 1e6) + shouldCommit = shouldCommit && (timestamp-commitTime >= w.recommit.Nanoseconds()/1e6) } if shouldCommit { @@ -1530,4 +1530,4 @@ func (w *worker) shouldCommit(timestamp int64) (bool, *types.Block) { w.commitWorkEnv.commitTime = time.Now().UnixNano() / 1e6 } return shouldCommit, highestLogicalBlock -} \ No newline at end of file +} diff --git a/mpc/mpc_processor_off_windows_amd64.go b/mpc/mpc_processor_off_windows_amd64.go new file mode 100644 index 0000000000..ebabc17ee8 --- /dev/null +++ b/mpc/mpc_processor_off_windows_amd64.go @@ -0,0 +1,104 @@ +// +build !mpcon + +package mpc + +// test part - no libso + +/* +#include +#include + +void notify_security_init(const char* icecfg, const char* url) { + //printf("init : icecfg : %s, url : %s", icecfg, url); +} + +void notify_security_calculation(const char* taskid, const char* pubkey, const char* address, const char* ir_address, const char* method, const char* extra) { + printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"); + printf("Received Params: taskId:%s, pubkey:%s, addr:%s, irAddr:%s, method:%s, extra:%s", taskid, pubkey, address, ir_address, method, extra); +} +*/ +import "C" + +// Main part, call library form + +/* +#cgo LDFLAGS: -Wl,-rpath="./libs" +#cgo LDFLAGS: -L./libs +#cgo LDFLAGS: -ljuzixmpcvm_platonsdk_demo +#include +#include + +extern int notify_security_calculation(const char* taskid, const char* pubkey, const char* address, const char* ir_address, const char* method, const char* extra); +*/ +//import "C" + +import ( + "github.com/PlatONnetwork/PlatON-Go/common" + "github.com/PlatONnetwork/PlatON-Go/log" + "fmt" + "unsafe" +) + +//void notify_security_calculation(const char* taskid, const char* pubkey, const char* address, const char* ir_address, const char* method, const char* extra) + +type MPCParams struct { + TaskId string + Pubkey string + From common.Address + IRAddr common.Address + Method string + Extra string +} + +func InitVM(icepath string, httpEndpoint string) { + cCfg := C.CString(icepath) + cUrl := C.CString(httpEndpoint) + defer func() { + C.free(unsafe.Pointer(cCfg)) + C.free(unsafe.Pointer(cUrl)) + }() + C.notify_security_init(cCfg, cUrl) + fmt.Println("mpc_process initVM method...") + log.Info("Init mpc processor success", "osType", "window", "icepath", icepath, "httpEndpoint", httpEndpoint) +} + +// for test +func ExecuteMPCTxForRedis(params MPCParams) (err error) { + return nil +} + +func ExecuteMPCTx(params MPCParams) error { + + cTaskId := C.CString(params.TaskId) + cPubKey := C.CString(params.Pubkey) + cAddr := C.CString(params.From.Hex()) + cIRAddr := C.CString(params.IRAddr.Hex()) + cMethod := C.CString(params.Method) + cExtra := C.CString(params.Extra) + + // call interface + C.notify_security_calculation(cTaskId, cPubKey, cAddr, cIRAddr, cMethod, cExtra) + + defer func() { + // free memory + C.free(unsafe.Pointer(cTaskId)) + C.free(unsafe.Pointer(cPubKey)) + C.free(unsafe.Pointer(cAddr)) + C.free(unsafe.Pointer(cIRAddr)) + C.free(unsafe.Pointer(cMethod)) + C.free(unsafe.Pointer(cExtra)) + }() + + fmt.Printf("02->Received param, the taskId: %v, the pubkey: %v, the from: %v, the irAddr: %v, the method: %v, the extra: %v \n", + params.TaskId, params.Pubkey, params.From.Hex(), params.IRAddr.Hex(), params.Method, params.Extra) + + log.Trace("Notify mvm success, ExecuteMPCTx method invoke success.", + "taskId", params.TaskId, + "pubkey", params.Pubkey, + "from", params.From.Hex(), + "irAddr", params.IRAddr.Hex(), + "method", params.Method) + + return nil + +} \ No newline at end of file diff --git a/mpc/mpc_processor_on_windows_amd64.go b/mpc/mpc_processor_on_windows_amd64.go new file mode 100644 index 0000000000..bf523db4ce --- /dev/null +++ b/mpc/mpc_processor_on_windows_amd64.go @@ -0,0 +1,105 @@ +// +build mpcon + +package mpc + +/* +#include +#include +*/ +import "C" + +import ( + "fmt" + "github.com/PlatONnetwork/PlatON-Go/common" + "github.com/PlatONnetwork/PlatON-Go/log" + "path/filepath" + "syscall" + "unsafe" +) + +var ( + psdkdll *syscall.DLL + securityInitProc *syscall.Proc + securityCalculation *syscall.Proc +) + +type MPCParams struct { + TaskId string + Pubkey string + From common.Address + IRAddr common.Address + Method string + Extra string +} + +func InitVM(icepath string, httpEndpoint string) { + // set default path of mpcLib. + workDir, _ := filepath.Abs("") + libPath := filepath.Join(workDir, "mpclib") + + // init ptr + libPathPtr, _ := syscall.UTF16PtrFromString(libPath) + syscall.SetCurrentDirectory(libPathPtr) + psdkdll = syscall.MustLoadDLL("mpc_vm_platonsdk.dll") + securityInitProc = psdkdll.MustFindProc("notify_security_init") + securityCalculation = psdkdll.MustFindProc("notify_security_calculation") + + // convert type + cCfg := C.CString(icepath) + cUrl := C.CString(httpEndpoint) + + cfgUintPtr := uintptr(unsafe.Pointer(cCfg)) + urlUintPtr := uintptr(unsafe.Pointer(cUrl)) + syscall.Syscall(securityInitProc.Addr(), 2, cfgUintPtr, urlUintPtr, 0) + + fmt.Println("mpc_process initVM method...") + log.Info("Init mpc processor success", "osType", "window", "icepath", icepath, "httpEndpoint", httpEndpoint) + defer func() { + C.free(unsafe.Pointer(cCfg)) + C.free(unsafe.Pointer(cUrl)) + }() +} + +func ExecuteMPCTx(params MPCParams) error { + + defer func() { + if err := recover(); err != nil { + log.Error("execute mpc tx fail.", "err", err) + } + }() + + cTaskId := C.CString(params.TaskId) + cPubKey := C.CString(params.Pubkey) + cAddr := C.CString(params.From.Hex()) + cIRAddr := C.CString(params.IRAddr.Hex()) + cMethod := C.CString(params.Method) + cExtra := C.CString(params.Extra) + + // convert to uintptr + taskIdUintPtr := uintptr(unsafe.Pointer(cTaskId)) + pubKeyUintPtr := uintptr(unsafe.Pointer(cPubKey)) + addrUintPtr := uintptr(unsafe.Pointer(cAddr)) + irAddrUintPtr := uintptr(unsafe.Pointer(cIRAddr)) + methodUintPtr := uintptr(unsafe.Pointer(cMethod)) + extraUintPtr := uintptr(unsafe.Pointer(cExtra)) + + syscall.Syscall6(securityCalculation.Addr(), 6, taskIdUintPtr, pubKeyUintPtr, addrUintPtr, irAddrUintPtr, methodUintPtr, extraUintPtr) + + defer func() { + C.free(unsafe.Pointer(cTaskId)) + C.free(unsafe.Pointer(cPubKey)) + C.free(unsafe.Pointer(cAddr)) + C.free(unsafe.Pointer(cIRAddr)) + C.free(unsafe.Pointer(cMethod)) + C.free(unsafe.Pointer(cExtra)) + }() + + log.Info("Notify mvm success, ExecuteMPCTx method invoke success.", + "taskId", params.TaskId, + "pubkey", params.Pubkey, + "from", params.From.Hex(), + "irAddr", params.IRAddr.Hex(), + "method", params.Method) + + return nil +} \ No newline at end of file diff --git a/params/bootnodes.go b/params/bootnodes.go index 9c57f39803..0aed19c1e2 100644 --- a/params/bootnodes.go +++ b/params/bootnodes.go @@ -22,7 +22,15 @@ var MainnetBootnodes = []string{} // TestnetBootnodes are the enode URLs of the P2P bootstrap nodes running on the // Ropsten test network. -var TestnetBootnodes = []string{} +var TestnetBootnodes = []string{ + "enode://a6ef31a2006f55f5039e23ccccef343e735d56699bde947cfe253d441f5f291561640a8e2bbaf8a85a8a367b939efcef6f80ae28d2bd3d0b21bdac01c3aa6f2f@test-sea.platon.network:16789", //TEST-SEA + "enode://d124e660938dc3fd63d913ff753fafc262764b22294431e760b572b0b58d5e6b813b32ccbacc326c03171542ae0ff8ff6528625a2d612e0c49240f111eba3c22@test-sg.platon.network:16790", //TEST-SG + "enode://24b0c456ae5cad46c4fb9bc02c867b997e22f30696e6e330926f785ca2e7410baf1eb34ffd9b5b07b5ba6e02b693faf57afb33f7c66cfbcf4c9186b4bfac737d@test-na.platon.network:16789", //TEST-NA + "enode://c7fc34d6d8b3d894a35895aaf2f788ed445e03b7673f7ce820aa6fdc02908eeab6982b7eb97e983cc708bcec093b3bc512b0b1fbf668e6ab94cd91f2d642e591@test-us.platon.network:16790", //TEST-US + "enode://9871adb2f926dffa3ff6060e07ae85295ce4184d5881cc761e465ca59597a7c5fa46b589557b0be62b759344fec50313a69b5fbda8b420f058ede85dadcecc4a@test-sg-soga.platon.network:16789", //TEST-SEA-SOGA + "enode://73323061805daa21ad07aa31cf0cc8c2295b05cff47c9ecb25c7a215c1c720df6c8698e94632346654cc4d8c0e99688f367626f20db9be85f29e9f41c29ffb92@test-siga-soga.platon.network:16790", //TEST-SG-SOGA + "enode://23aa343260d06e04107d1cd9a7d12c54cc238719a1523ffe42640210c913218b5940d41511c5adb716da38844a85cdab8b7db0600d242e24168d7df10aebd324@test-si-syde.platon.network:16789", //TEST-SI-SYDE +} // RinkebyBootnodes are the enode URLs of the P2P bootstrap nodes running on the // Rinkeby test network. diff --git a/params/config.go b/params/config.go index 3db7b425eb..7ab23ce4b5 100644 --- a/params/config.go +++ b/params/config.go @@ -33,15 +33,15 @@ var ( var ( initialConsensusNodes = []string{ - "enode://1f3a8672348ff6b789e416762ad53e69063138b8eb4d8780101658f24b2369f1a8e09499226b467d8bc0c4e03e1dc903df857eeb3c67733d21b6aaee2840e429@192.168.9.181:16789", - "enode://751f4f62fccee84fc290d0c68d673e4b0cc6975a5747d2baccb20f954d59ba3315d7bfb6d831523624d003c8c2d33451129e67c3eef3098f711ef3b3e268fd3c@192.168.9.182:16789", - "enode://b6c8c9f99bfebfa4fb174df720b9385dbd398de699ec36750af3f38f8e310d4f0b90447acbef64bdf924c4b59280f3d42bb256e6123b53e9a7e99e4c432549d6@192.168.9.183:16789", - //"enode://97e424be5e58bfd4533303f8f515211599fd4ffe208646f7bfdf27885e50b6dd85d957587180988e76ae77b4b6563820a27b16885419e5ba6f575f19f6cb36b0@192.168.9.184:16789", + "enode://a6ef31a2006f55f5039e23ccccef343e735d56699bde947cfe253d441f5f291561640a8e2bbaf8a85a8a367b939efcef6f80ae28d2bd3d0b21bdac01c3aa6f2f@test-sea.platon.network:16789", //TEST-SEA + "enode://d124e660938dc3fd63d913ff753fafc262764b22294431e760b572b0b58d5e6b813b32ccbacc326c03171542ae0ff8ff6528625a2d612e0c49240f111eba3c22@test-sg.platon.network:16790", //TEST-SG + "enode://24b0c456ae5cad46c4fb9bc02c867b997e22f30696e6e330926f785ca2e7410baf1eb34ffd9b5b07b5ba6e02b693faf57afb33f7c66cfbcf4c9186b4bfac737d@test-na.platon.network:16789", //TEST-NA + "enode://c7fc34d6d8b3d894a35895aaf2f788ed445e03b7673f7ce820aa6fdc02908eeab6982b7eb97e983cc708bcec093b3bc512b0b1fbf668e6ab94cd91f2d642e591@test-us.platon.network:16790", //TEST-US } // MainnetChainConfig is the chain parameters to run a node on the main network. MainnetChainConfig = &ChainConfig{ - ChainID: big.NewInt(1), + ChainID: big.NewInt(101), HomesteadBlock: big.NewInt(1150000), DAOForkBlock: big.NewInt(1920000), DAOForkSupport: true, @@ -69,17 +69,21 @@ var ( // TestnetChainConfig contains the chain parameters to run a node on the Ropsten test network. TestnetChainConfig = &ChainConfig{ - ChainID: big.NewInt(3), - HomesteadBlock: big.NewInt(0), + ChainID: big.NewInt(103), + HomesteadBlock: big.NewInt(1), DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), - EIP155Block: big.NewInt(10), - EIP158Block: big.NewInt(10), - ByzantiumBlock: big.NewInt(1700000), + DAOForkSupport: false, + EIP150Block: big.NewInt(2), + EIP150Hash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"), + EIP155Block: big.NewInt(3), + EIP158Block: big.NewInt(3), + ByzantiumBlock: big.NewInt(4), ConstantinopleBlock: nil, - Ethash: new(EthashConfig), + //Ethash: new(EthashConfig), + Cbft: &CbftConfig{ + InitialNodes: convertNodeUrl(initialConsensusNodes), + }, + VMInterpreter: "wasm", } // TestnetTrustedCheckpoint contains the light client trusted checkpoint for the Ropsten test network. @@ -93,7 +97,7 @@ var ( // RinkebyChainConfig contains the chain parameters to run a node on the Rinkeby test network. RinkebyChainConfig = &ChainConfig{ - ChainID: big.NewInt(4), + ChainID: big.NewInt(104), HomesteadBlock: big.NewInt(1), DAOForkBlock: nil, DAOForkSupport: true, @@ -128,13 +132,13 @@ var ( CandidateConfig: &CandidateConfig{ Threshold: "1000000000000000000000000", DepositLimit: 10, - Allowed: 100, + Allowed: 512, MaxChair: 10, MaxCount: 100, RefundBlockNumber: 512, }, TicketConfig: &TicketConfig{ - TicketPrice: "1000000000000000000", + TicketPrice: "100000000000000000000", MaxCount: 51200, ExpireBlockNumber: 1536000, }, diff --git a/trie/database.go b/trie/database.go index 7af63c1403..ba6266521e 100644 --- a/trie/database.go +++ b/trie/database.go @@ -375,8 +375,11 @@ func (db *Database) preimage(hash common.Hash) ([]byte, error) { if preimage != nil { return preimage, nil } + secureKey := make([]byte, secureKeyLength) + secureKey = append(secureKey[:0], secureKeyPrefix...) + secureKey = append(secureKey, hash[:]...) // Content unavailable in memory, attempt to retrieve from disk - return db.diskdb.Get(db.secureKey(hash[:])) + return db.diskdb.Get(secureKey) } // secureKey returns the database key for the preimage of key, as an ephemeral diff --git a/trie/secure_trie.go b/trie/secure_trie.go index 00cb9796b0..35f7b7a721 100644 --- a/trie/secure_trie.go +++ b/trie/secure_trie.go @@ -35,6 +35,7 @@ import ( // SecureTrie is not safe for concurrent use. type SecureTrie struct { trie Trie + storageValue map[common.Hash][]byte hashKeyBuf [common.HashLength]byte secKeyCache map[string][]byte secKeyCacheOwner *SecureTrie // Pointer to self, replace the key cache on mismatch @@ -55,12 +56,14 @@ func NewSecure(root common.Hash, db *Database, cachelimit uint16) (*SecureTrie, if db == nil { panic("trie.NewSecure called without a database") } + log.Debug("------NewSecure------", "GoRoutineID", common.CurrentGoRoutineID(), "root", root) trie, err := New(root, db) + storageValue := make(map[common.Hash][]byte) if err != nil { return nil, err } trie.SetCacheLimit(cachelimit) - return &SecureTrie{trie: *trie}, nil + return &SecureTrie{trie: *trie, storageValue: storageValue}, nil } // Get returns the value for key stored in the trie. @@ -111,6 +114,8 @@ func (t *SecureTrie) TryUpdate(key, value []byte) error { } func (t *SecureTrie) TryUpdateValue(key, value []byte) error { + hash := common.BytesToHash(key) + t.storageValue[hash] = value t.getSecKeyCache()[string(key)] = common.CopyBytes(value) return nil } @@ -137,6 +142,9 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte { if key, ok := t.getSecKeyCache()[string(shaKey)]; ok { return key } + if key, ok := t.storageValue[common.BytesToHash(shaKey)]; ok { + return key + } key, _ := t.trie.db.preimage(common.BytesToHash(shaKey)) return key } @@ -148,15 +156,18 @@ func (t *SecureTrie) GetKey(shaKey []byte) []byte { // from the database. func (t *SecureTrie) Commit(onleaf LeafCallback) (root common.Hash, err error) { // Write all the pre-images to the actual disk database + t.trie.db.lock.Lock() if len(t.getSecKeyCache()) > 0 { - t.trie.db.lock.Lock() for hk, key := range t.secKeyCache { t.trie.db.insertPreimage(common.BytesToHash([]byte(hk)), key) } - t.trie.db.lock.Unlock() - t.secKeyCache = make(map[string][]byte) } + for k, v := range t.storageValue { + t.trie.db.insertPreimage(k, v) + } + t.trie.db.lock.Unlock() + // Commit the trie to its intermediate node database return t.trie.Commit(onleaf) } @@ -175,8 +186,17 @@ func (t *SecureTrie) Root() []byte { // Copy returns a copy of SecureTrie. func (t *SecureTrie) Copy() *SecureTrie { - cpy := *t - return &cpy + cpy := &SecureTrie{ + trie: t.trie, + storageValue: make(map[common.Hash][]byte), + secKeyCache: t.secKeyCache, + secKeyCacheOwner: t.secKeyCacheOwner, + } + for k, v := range t.storageValue { + cpy.storageValue[k] = v + } + + return cpy } // NodeIterator returns an iterator that returns nodes of the underlying trie. Iteration diff --git a/trie/trie.go b/trie/trie.go index 7f3d267675..587f2644c8 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -32,7 +32,8 @@ var ( emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421") // emptyState is the known hash of an empty state trie entry. - emptyState = crypto.Keccak256Hash(nil) + emptyState = crypto.Keccak256Hash(nil) + emptyStorage = crypto.Keccak256Hash(nil) ) var ( @@ -102,6 +103,7 @@ func New(root common.Hash, db *Database) (*Trie, error) { originalRoot: root, } // If root is not empty, restore the node from the DB (the whole tree) + log.Info("------New trie------", "GoRoutineID", common.CurrentGoRoutineID(), "root", root) if root != (common.Hash{}) && root != emptyRoot { rootnode, err := trie.resolveHash(root[:], nil) if err != nil { diff --git a/vendor/github.com/go-errors/errors/LICENSE.MIT b/vendor/github.com/go-errors/errors/LICENSE.MIT new file mode 100644 index 0000000000..c9a5b2eeb7 --- /dev/null +++ b/vendor/github.com/go-errors/errors/LICENSE.MIT @@ -0,0 +1,7 @@ +Copyright (c) 2015 Conrad Irwin + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/go-errors/errors/README.md b/vendor/github.com/go-errors/errors/README.md new file mode 100644 index 0000000000..5d4f1873dd --- /dev/null +++ b/vendor/github.com/go-errors/errors/README.md @@ -0,0 +1,66 @@ +go-errors/errors +================ + +[![Build Status](https://travis-ci.org/go-errors/errors.svg?branch=master)](https://travis-ci.org/go-errors/errors) + +Package errors adds stacktrace support to errors in go. + +This is particularly useful when you want to understand the state of execution +when an error was returned unexpectedly. + +It provides the type \*Error which implements the standard golang error +interface, so you can use this library interchangably with code that is +expecting a normal error return. + +Usage +----- + +Full documentation is available on +[godoc](https://godoc.org/github.com/go-errors/errors), but here's a simple +example: + +```go +package crashy + +import "github.com/go-errors/errors" + +var Crashed = errors.Errorf("oh dear") + +func Crash() error { + return errors.New(Crashed) +} +``` + +This can be called as follows: + +```go +package main + +import ( + "crashy" + "fmt" + "github.com/go-errors/errors" +) + +func main() { + err := crashy.Crash() + if err != nil { + if errors.Is(err, crashy.Crashed) { + fmt.Println(err.(*errors.Error).ErrorStack()) + } else { + panic(err) + } + } +} +``` + +Meta-fu +------- + +This package was original written to allow reporting to +[Bugsnag](https://bugsnag.com/) from +[bugsnag-go](https://github.com/bugsnag/bugsnag-go), but after I found similar +packages by Facebook and Dropbox, it was moved to one canonical location so +everyone can benefit. + +This package is licensed under the MIT license, see LICENSE.MIT for details. diff --git a/vendor/github.com/go-errors/errors/cover.out b/vendor/github.com/go-errors/errors/cover.out new file mode 100644 index 0000000000..ab18b0519f --- /dev/null +++ b/vendor/github.com/go-errors/errors/cover.out @@ -0,0 +1,89 @@ +mode: set +github.com/go-errors/errors/stackframe.go:27.51,30.25 2 1 +github.com/go-errors/errors/stackframe.go:33.2,38.8 3 1 +github.com/go-errors/errors/stackframe.go:30.25,32.3 1 0 +github.com/go-errors/errors/stackframe.go:43.47,44.31 1 1 +github.com/go-errors/errors/stackframe.go:47.2,47.48 1 1 +github.com/go-errors/errors/stackframe.go:44.31,46.3 1 1 +github.com/go-errors/errors/stackframe.go:52.42,56.16 3 1 +github.com/go-errors/errors/stackframe.go:60.2,60.60 1 1 +github.com/go-errors/errors/stackframe.go:56.16,58.3 1 0 +github.com/go-errors/errors/stackframe.go:64.55,67.16 2 1 +github.com/go-errors/errors/stackframe.go:71.2,72.61 2 1 +github.com/go-errors/errors/stackframe.go:76.2,76.66 1 1 +github.com/go-errors/errors/stackframe.go:67.16,69.3 1 0 +github.com/go-errors/errors/stackframe.go:72.61,74.3 1 0 +github.com/go-errors/errors/stackframe.go:79.56,91.63 3 1 +github.com/go-errors/errors/stackframe.go:95.2,95.53 1 1 +github.com/go-errors/errors/stackframe.go:100.2,101.18 2 1 +github.com/go-errors/errors/stackframe.go:91.63,94.3 2 1 +github.com/go-errors/errors/stackframe.go:95.53,98.3 2 1 +github.com/go-errors/errors/error.go:70.32,73.23 2 1 +github.com/go-errors/errors/error.go:80.2,85.3 3 1 +github.com/go-errors/errors/error.go:74.2,75.10 1 1 +github.com/go-errors/errors/error.go:76.2,77.28 1 1 +github.com/go-errors/errors/error.go:92.43,95.23 2 1 +github.com/go-errors/errors/error.go:104.2,109.3 3 1 +github.com/go-errors/errors/error.go:96.2,97.11 1 1 +github.com/go-errors/errors/error.go:98.2,99.10 1 1 +github.com/go-errors/errors/error.go:100.2,101.28 1 1 +github.com/go-errors/errors/error.go:115.39,117.19 1 1 +github.com/go-errors/errors/error.go:121.2,121.29 1 1 +github.com/go-errors/errors/error.go:125.2,125.43 1 1 +github.com/go-errors/errors/error.go:129.2,129.14 1 1 +github.com/go-errors/errors/error.go:117.19,119.3 1 1 +github.com/go-errors/errors/error.go:121.29,123.3 1 1 +github.com/go-errors/errors/error.go:125.43,127.3 1 1 +github.com/go-errors/errors/error.go:135.53,137.2 1 1 +github.com/go-errors/errors/error.go:140.34,142.2 1 1 +github.com/go-errors/errors/error.go:146.34,149.42 2 1 +github.com/go-errors/errors/error.go:153.2,153.20 1 1 +github.com/go-errors/errors/error.go:149.42,151.3 1 1 +github.com/go-errors/errors/error.go:158.39,160.2 1 1 +github.com/go-errors/errors/error.go:164.46,165.23 1 1 +github.com/go-errors/errors/error.go:173.2,173.19 1 1 +github.com/go-errors/errors/error.go:165.23,168.32 2 1 +github.com/go-errors/errors/error.go:168.32,170.4 1 1 +github.com/go-errors/errors/error.go:177.37,178.42 1 1 +github.com/go-errors/errors/error.go:181.2,181.41 1 1 +github.com/go-errors/errors/error.go:178.42,180.3 1 1 +github.com/go-errors/errors/parse_panic.go:10.39,12.2 1 1 +github.com/go-errors/errors/parse_panic.go:16.46,24.34 5 1 +github.com/go-errors/errors/parse_panic.go:70.2,70.43 1 1 +github.com/go-errors/errors/parse_panic.go:73.2,73.55 1 0 +github.com/go-errors/errors/parse_panic.go:24.34,27.23 2 1 +github.com/go-errors/errors/parse_panic.go:27.23,28.42 1 1 +github.com/go-errors/errors/parse_panic.go:28.42,31.5 2 1 +github.com/go-errors/errors/parse_panic.go:31.6,33.5 1 0 +github.com/go-errors/errors/parse_panic.go:35.5,35.29 1 1 +github.com/go-errors/errors/parse_panic.go:35.29,36.86 1 1 +github.com/go-errors/errors/parse_panic.go:36.86,38.5 1 1 +github.com/go-errors/errors/parse_panic.go:40.5,40.32 1 1 +github.com/go-errors/errors/parse_panic.go:40.32,41.18 1 1 +github.com/go-errors/errors/parse_panic.go:45.4,46.46 2 1 +github.com/go-errors/errors/parse_panic.go:51.4,53.23 2 1 +github.com/go-errors/errors/parse_panic.go:57.4,58.18 2 1 +github.com/go-errors/errors/parse_panic.go:62.4,63.17 2 1 +github.com/go-errors/errors/parse_panic.go:41.18,43.10 2 1 +github.com/go-errors/errors/parse_panic.go:46.46,49.5 2 1 +github.com/go-errors/errors/parse_panic.go:53.23,55.5 1 0 +github.com/go-errors/errors/parse_panic.go:58.18,60.5 1 0 +github.com/go-errors/errors/parse_panic.go:63.17,65.10 2 1 +github.com/go-errors/errors/parse_panic.go:70.43,72.3 1 1 +github.com/go-errors/errors/parse_panic.go:80.85,82.29 2 1 +github.com/go-errors/errors/parse_panic.go:85.2,85.15 1 1 +github.com/go-errors/errors/parse_panic.go:88.2,90.63 2 1 +github.com/go-errors/errors/parse_panic.go:94.2,94.53 1 1 +github.com/go-errors/errors/parse_panic.go:99.2,101.36 2 1 +github.com/go-errors/errors/parse_panic.go:105.2,106.15 2 1 +github.com/go-errors/errors/parse_panic.go:109.2,112.49 3 1 +github.com/go-errors/errors/parse_panic.go:116.2,117.16 2 1 +github.com/go-errors/errors/parse_panic.go:121.2,126.8 1 1 +github.com/go-errors/errors/parse_panic.go:82.29,84.3 1 0 +github.com/go-errors/errors/parse_panic.go:85.15,87.3 1 1 +github.com/go-errors/errors/parse_panic.go:90.63,93.3 2 1 +github.com/go-errors/errors/parse_panic.go:94.53,97.3 2 1 +github.com/go-errors/errors/parse_panic.go:101.36,103.3 1 0 +github.com/go-errors/errors/parse_panic.go:106.15,108.3 1 0 +github.com/go-errors/errors/parse_panic.go:112.49,114.3 1 1 +github.com/go-errors/errors/parse_panic.go:117.16,119.3 1 0 diff --git a/vendor/github.com/go-errors/errors/error.go b/vendor/github.com/go-errors/errors/error.go new file mode 100644 index 0000000000..ea5d2b206a --- /dev/null +++ b/vendor/github.com/go-errors/errors/error.go @@ -0,0 +1,224 @@ +// Package errors provides errors that have stack-traces. +// +// This is particularly useful when you want to understand the +// state of execution when an error was returned unexpectedly. +// +// It provides the type *Error which implements the standard +// golang error interface, so you can use this library interchangably +// with code that is expecting a normal error return. +// +// For example: +// +// package crashy +// +// import "github.com/go-errors/errors" +// +// var Crashed = errors.Errorf("oh dear") +// +// func Crash() error { +// return errors.New(Crashed) +// } +// +// This can be called as follows: +// +// package main +// +// import ( +// "crashy" +// "fmt" +// "github.com/go-errors/errors" +// ) +// +// func main() { +// err := crashy.Crash() +// if err != nil { +// if errors.Is(err, crashy.Crashed) { +// fmt.Println(err.(*errors.Error).ErrorStack()) +// } else { +// panic(err) +// } +// } +// } +// +// This package was original written to allow reporting to Bugsnag, +// but after I found similar packages by Facebook and Dropbox, it +// was moved to one canonical location so everyone can benefit. +package errors + +import ( + "bytes" + "fmt" + "reflect" + "runtime" +) + +// The maximum number of stackframes on any error. +var MaxStackDepth = 50 + +// Error is an error with an attached stacktrace. It can be used +// wherever the builtin error interface is expected. +type Error struct { + Err error + stack []uintptr + frames []StackFrame + prefix string +} + +// New makes an Error from the given value. If that value is already an +// error then it will be used directly, if not, it will be passed to +// fmt.Errorf("%v"). The stacktrace will point to the line of code that +// called New. +func New(e interface{}) *Error { + var err error + + switch e := e.(type) { + case error: + err = e + default: + err = fmt.Errorf("%v", e) + } + + stack := make([]uintptr, MaxStackDepth) + length := runtime.Callers(2, stack[:]) + return &Error{ + Err: err, + stack: stack[:length], + } +} + +// Wrap makes an Error from the given value. If that value is already an +// error then it will be used directly, if not, it will be passed to +// fmt.Errorf("%v"). The skip parameter indicates how far up the stack +// to start the stacktrace. 0 is from the current call, 1 from its caller, etc. +func Wrap(e interface{}, skip int) *Error { + if e == nil { + return nil + } + + var err error + + switch e := e.(type) { + case *Error: + return e + case error: + err = e + default: + err = fmt.Errorf("%v", e) + } + + stack := make([]uintptr, MaxStackDepth) + length := runtime.Callers(2+skip, stack[:]) + return &Error{ + Err: err, + stack: stack[:length], + } +} + +// WrapPrefix makes an Error from the given value. If that value is already an +// error then it will be used directly, if not, it will be passed to +// fmt.Errorf("%v"). The prefix parameter is used to add a prefix to the +// error message when calling Error(). The skip parameter indicates how far +// up the stack to start the stacktrace. 0 is from the current call, +// 1 from its caller, etc. +func WrapPrefix(e interface{}, prefix string, skip int) *Error { + if e == nil { + return nil + } + + err := Wrap(e, 1+skip) + + if err.prefix != "" { + prefix = fmt.Sprintf("%s: %s", prefix, err.prefix) + } + + return &Error{ + Err: err.Err, + stack: err.stack, + prefix: prefix, + } + +} + +// Is detects whether the error is equal to a given error. Errors +// are considered equal by this function if they are the same object, +// or if they both contain the same error inside an errors.Error. +func Is(e error, original error) bool { + + if e == original { + return true + } + + if e, ok := e.(*Error); ok { + return Is(e.Err, original) + } + + if original, ok := original.(*Error); ok { + return Is(e, original.Err) + } + + return false +} + +// Errorf creates a new error with the given message. You can use it +// as a drop-in replacement for fmt.Errorf() to provide descriptive +// errors in return values. +func Errorf(format string, a ...interface{}) *Error { + return Wrap(fmt.Errorf(format, a...), 1) +} + +// Error returns the underlying error's message. +func (err *Error) Error() string { + + msg := err.Err.Error() + if err.prefix != "" { + msg = fmt.Sprintf("%s: %s", err.prefix, msg) + } + + return msg +} + +// Stack returns the callstack formatted the same way that go does +// in runtime/debug.Stack() +func (err *Error) Stack() []byte { + buf := bytes.Buffer{} + + for _, frame := range err.StackFrames() { + buf.WriteString(frame.String()) + } + + return buf.Bytes() +} + +// Callers satisfies the bugsnag ErrorWithCallerS() interface +// so that the stack can be read out. +func (err *Error) Callers() []uintptr { + return err.stack +} + +// ErrorStack returns a string that contains both the +// error message and the callstack. +func (err *Error) ErrorStack() string { + return err.TypeName() + " " + err.Error() + "\n" + string(err.Stack()) +} + +// StackFrames returns an array of frames containing information about the +// stack. +func (err *Error) StackFrames() []StackFrame { + if err.frames == nil { + err.frames = make([]StackFrame, len(err.stack)) + + for i, pc := range err.stack { + err.frames[i] = NewStackFrame(pc) + } + } + + return err.frames +} + +// TypeName returns the type this error. e.g. *errors.stringError. +func (err *Error) TypeName() string { + if _, ok := err.Err.(uncaughtPanic); ok { + return "panic" + } + return reflect.TypeOf(err.Err).String() +} diff --git a/vendor/github.com/go-errors/errors/parse_panic.go b/vendor/github.com/go-errors/errors/parse_panic.go new file mode 100644 index 0000000000..cc37052d78 --- /dev/null +++ b/vendor/github.com/go-errors/errors/parse_panic.go @@ -0,0 +1,127 @@ +package errors + +import ( + "strconv" + "strings" +) + +type uncaughtPanic struct{ message string } + +func (p uncaughtPanic) Error() string { + return p.message +} + +// ParsePanic allows you to get an error object from the output of a go program +// that panicked. This is particularly useful with https://github.com/mitchellh/panicwrap. +func ParsePanic(text string) (*Error, error) { + lines := strings.Split(text, "\n") + + state := "start" + + var message string + var stack []StackFrame + + for i := 0; i < len(lines); i++ { + line := lines[i] + + if state == "start" { + if strings.HasPrefix(line, "panic: ") { + message = strings.TrimPrefix(line, "panic: ") + state = "seek" + } else { + return nil, Errorf("bugsnag.panicParser: Invalid line (no prefix): %s", line) + } + + } else if state == "seek" { + if strings.HasPrefix(line, "goroutine ") && strings.HasSuffix(line, "[running]:") { + state = "parsing" + } + + } else if state == "parsing" { + if line == "" { + state = "done" + break + } + createdBy := false + if strings.HasPrefix(line, "created by ") { + line = strings.TrimPrefix(line, "created by ") + createdBy = true + } + + i++ + + if i >= len(lines) { + return nil, Errorf("bugsnag.panicParser: Invalid line (unpaired): %s", line) + } + + frame, err := parsePanicFrame(line, lines[i], createdBy) + if err != nil { + return nil, err + } + + stack = append(stack, *frame) + if createdBy { + state = "done" + break + } + } + } + + if state == "done" || state == "parsing" { + return &Error{Err: uncaughtPanic{message}, frames: stack}, nil + } + return nil, Errorf("could not parse panic: %v", text) +} + +// The lines we're passing look like this: +// +// main.(*foo).destruct(0xc208067e98) +// /0/go/src/github.com/bugsnag/bugsnag-go/pan/main.go:22 +0x151 +func parsePanicFrame(name string, line string, createdBy bool) (*StackFrame, error) { + idx := strings.LastIndex(name, "(") + if idx == -1 && !createdBy { + return nil, Errorf("bugsnag.panicParser: Invalid line (no call): %s", name) + } + if idx != -1 { + name = name[:idx] + } + pkg := "" + + if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 { + pkg += name[:lastslash] + "/" + name = name[lastslash+1:] + } + if period := strings.Index(name, "."); period >= 0 { + pkg += name[:period] + name = name[period+1:] + } + + name = strings.Replace(name, "·", ".", -1) + + if !strings.HasPrefix(line, "\t") { + return nil, Errorf("bugsnag.panicParser: Invalid line (no tab): %s", line) + } + + idx = strings.LastIndex(line, ":") + if idx == -1 { + return nil, Errorf("bugsnag.panicParser: Invalid line (no line number): %s", line) + } + file := line[1:idx] + + number := line[idx+1:] + if idx = strings.Index(number, " +"); idx > -1 { + number = number[:idx] + } + + lno, err := strconv.ParseInt(number, 10, 32) + if err != nil { + return nil, Errorf("bugsnag.panicParser: Invalid line (bad line number): %s", line) + } + + return &StackFrame{ + File: file, + LineNumber: int(lno), + Package: pkg, + Name: name, + }, nil +} diff --git a/vendor/github.com/go-errors/errors/stackframe.go b/vendor/github.com/go-errors/errors/stackframe.go new file mode 100644 index 0000000000..750ab9a521 --- /dev/null +++ b/vendor/github.com/go-errors/errors/stackframe.go @@ -0,0 +1,102 @@ +package errors + +import ( + "bytes" + "fmt" + "io/ioutil" + "runtime" + "strings" +) + +// A StackFrame contains all necessary information about to generate a line +// in a callstack. +type StackFrame struct { + // The path to the file containing this ProgramCounter + File string + // The LineNumber in that file + LineNumber int + // The Name of the function that contains this ProgramCounter + Name string + // The Package that contains this function + Package string + // The underlying ProgramCounter + ProgramCounter uintptr +} + +// NewStackFrame popoulates a stack frame object from the program counter. +func NewStackFrame(pc uintptr) (frame StackFrame) { + + frame = StackFrame{ProgramCounter: pc} + if frame.Func() == nil { + return + } + frame.Package, frame.Name = packageAndName(frame.Func()) + + // pc -1 because the program counters we use are usually return addresses, + // and we want to show the line that corresponds to the function call + frame.File, frame.LineNumber = frame.Func().FileLine(pc - 1) + return + +} + +// Func returns the function that contained this frame. +func (frame *StackFrame) Func() *runtime.Func { + if frame.ProgramCounter == 0 { + return nil + } + return runtime.FuncForPC(frame.ProgramCounter) +} + +// String returns the stackframe formatted in the same way as go does +// in runtime/debug.Stack() +func (frame *StackFrame) String() string { + str := fmt.Sprintf("%s:%d (0x%x)\n", frame.File, frame.LineNumber, frame.ProgramCounter) + + source, err := frame.SourceLine() + if err != nil { + return str + } + + return str + fmt.Sprintf("\t%s: %s\n", frame.Name, source) +} + +// SourceLine gets the line of code (from File and Line) of the original source if possible. +func (frame *StackFrame) SourceLine() (string, error) { + data, err := ioutil.ReadFile(frame.File) + + if err != nil { + return "", New(err) + } + + lines := bytes.Split(data, []byte{'\n'}) + if frame.LineNumber <= 0 || frame.LineNumber >= len(lines) { + return "???", nil + } + // -1 because line-numbers are 1 based, but our array is 0 based + return string(bytes.Trim(lines[frame.LineNumber-1], " \t")), nil +} + +func packageAndName(fn *runtime.Func) (string, string) { + name := fn.Name() + pkg := "" + + // The name includes the path name to the package, which is unnecessary + // since the file name is already included. Plus, it has center dots. + // That is, we see + // runtime/debug.*T·ptrmethod + // and want + // *T.ptrmethod + // Since the package path might contains dots (e.g. code.google.com/...), + // we first remove the path prefix if there is one. + if lastslash := strings.LastIndex(name, "/"); lastslash >= 0 { + pkg += name[:lastslash] + "/" + name = name[lastslash+1:] + } + if period := strings.Index(name, "."); period >= 0 { + pkg += name[:period] + name = name[period+1:] + } + + name = strings.Replace(name, "·", ".", -1) + return pkg, name +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 149eea3ddb..ed7e9d24c1 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -140,6 +140,12 @@ "revision": "991cd3d3809135dc24daf6188dc6edcaf3d7d2d9", "revisionTime": "2017-01-17T22:23:42Z" }, + { + "checksumSHA1": "kxja3mICEw4DKBlGQdK4tmIAkCQ=", + "path": "github.com/go-errors/errors", + "revision": "d98b870cc4e05f1545532a80e9909be8216095b6", + "revisionTime": "2018-08-13T16:29:53Z" + }, { "checksumSHA1": "CXz+lMUb7OO0p+5BjBA8paN7Sfc=", "origin": "github.com/PlatONnetwork/PlatON-Go/life/vendor/github.com/go-interpreter/wagon/disasm", @@ -990,5 +996,5 @@ "revisionTime": "2017-08-11T01:42:03Z" } ], - "rootPath": "Platon-go" + "rootPath": "github.com/PlatONnetwork/PlatON-Go" }