diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 1a7438cc5..126da75b6 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -1383,6 +1383,8 @@ func (b *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error // recover check point from genesis block if recoverFromDefault { + //reset all mem state data + b.CkpManager.OnReset() b.InitCheckpoint(nil, nil, nil) } @@ -1705,6 +1707,7 @@ func (b *BlockChain) connectBestChain(node *BlockNode, block *Block, confirm *pa // for future processing, so add the block to the side chain holding // cache. log.Debugf("Adding block %x to side chain cache", node.Hash.Bytes()) + b.blockCache[*node.Hash] = block b.confirmCache[*node.Hash] = confirm //b.Index[*node.Hash] = node @@ -1833,12 +1836,13 @@ func (b *BlockChain) ReorganizeChain2(block *Block) error { // 3. error func (b *BlockChain) processBlock(block *Block, confirm *payload.Confirm) (bool, bool, error) { blockHash := block.Hash() - log.Debugf("[ProcessBLock] height = %d, hash = %x", block.Header.Height, blockHash.Bytes()) // The block must not already exist in the main chain or side chains. exists := b.BlockExists(&blockHash) if exists { + b.blockCache[block.Hash()] = block + b.confirmCache[block.Hash()] = confirm str := fmt.Sprintf("already have block %x height %d\n ", blockHash.Bytes(), block.Height) return false, false, fmt.Errorf(str) } @@ -2019,7 +2023,6 @@ func (b *BlockChain) BlockLocatorFromHash(inhash *Uint256) []*Uint256 { // The desired block height is in the main chain, so look it up // from the main chain database. - h, err := b.GetBlockHash(uint32(blockHeight)) if err != nil { log.Debugf("Lookup of known valid height failed %v", blockHeight) diff --git a/blockchain/indexers/checkpoint.go b/blockchain/indexers/checkpoint.go index 660708a2c..2265843b2 100644 --- a/blockchain/indexers/checkpoint.go +++ b/blockchain/indexers/checkpoint.go @@ -41,6 +41,10 @@ func (c *Checkpoint) OnRollbackTo(height uint32) error { return nil } +func (c *Checkpoint) OnReset() error { + return nil +} + func (c *Checkpoint) OnRollbackSeekTo(height uint32) { return } diff --git a/blockchain/txvalidator.go b/blockchain/txvalidator.go index a42d572a7..12161edce 100644 --- a/blockchain/txvalidator.go +++ b/blockchain/txvalidator.go @@ -841,9 +841,6 @@ func CheckCRTransactionSignature(signature []byte, code []byte, data []byte) err return err } } else if signType == vm.CHECKMULTISIG { - return errors.New("CR not support multi sign code") - - // check code and signature if err := CheckMultiSigSignatures(program.Program{ Code: code, Parameter: signature, diff --git a/cmd/script/api/dposmanager.go b/cmd/script/api/dposmanager.go index 1e378aa74..5c5aeb935 100644 --- a/cmd/script/api/dposmanager.go +++ b/cmd/script/api/dposmanager.go @@ -89,7 +89,7 @@ func newDposManager(L *lua.LState) int { TimeSource: medianTime, }) - mockManager.Consensus = NewConsensus(dposManager, 5*time.Second, mockManager.Handler, math.MaxUint32) + mockManager.Consensus = NewConsensus(dposManager, 5*time.Second, mockManager.Handler, math.MaxUint32, 0) mockManager.Dispatcher, mockManager.IllegalMonitor = NewDispatcherAndIllegalMonitor(ProposalDispatcherConfig{ EventMonitor: mockManager.EventMonitor, Consensus: mockManager.Consensus, diff --git a/common/common.go b/common/common.go index 7168bf574..e7a20b723 100644 --- a/common/common.go +++ b/common/common.go @@ -134,8 +134,8 @@ func VarIntSerializeSize(val uint64) int { return 9 } -//get ip string from addr string -//if addr is not the format x.x.x.x:port return empt string "" +// get ip string from addr string +// if addr is not the format x.x.x.x:port return empt string "" func GetIpFromAddr(addr string) string { endIndex := strings.Index(addr, ":") if endIndex < 0 { @@ -154,3 +154,11 @@ func IsLetterOrNumber(s string) bool { func GetNFTID(referkey, txHash Uint256) Uint256 { return Sha256D(append(referkey[:], txHash[:]...)) } + +// standard code return publickey, muticode return code +func GetOwnerKey(code []byte) []byte { + if len(code) == 35 { + return code[1 : len(code)-1] + } + return code +} diff --git a/common/config/config.go b/common/config/config.go index 326f864bd..261e4607e 100644 --- a/common/config/config.go +++ b/common/config/config.go @@ -378,7 +378,7 @@ func (p *Configuration) TestNet() *Configuration { p.ProhibitTransferToDIDHeight = 807000 p.DIDSideChainAddress = "XKUh4GLhFJiqAMTF6HyWQrV9pK9HcGUdfJ" p.DPoSV2StartHeight = 965800 + 720*3 - p.SupportMultiCodeHeight = 2000 + p.SupportMultiCodeHeight = 1171000 p.DPoSV2EffectiveVotes = 3000 * 100000000 p.DPoSConfiguration.DPoSV2DepositCoinMinLockTime = 7200 * 3 p.DPoSConfiguration.DPoSV2MinVotesLockTime = 7200 @@ -391,17 +391,17 @@ func (p *Configuration) TestNet() *Configuration { p.CrossChainMonitorInterval = 100 p.CRConfiguration.CRClaimPeriod = 10080 p.DPoSConfiguration.NFTStartHeight = 1098000 - p.DPoSConfiguration.NFTV2StartHeight = math.MaxUint32 // todo complete me - p.DPoSConfiguration.DexStartHeight = math.MaxUint32 // todo complete me + p.DPoSConfiguration.NFTV2StartHeight = 1171000 + p.DPoSConfiguration.DexStartHeight = 1171000 p.HttpInfoPort = 21333 p.HttpRestPort = 21334 p.HttpWsPort = 21335 p.HttpJsonPort = 21336 - p.ProducerSchnorrStartHeight = math.MaxUint32 - p.CRSchnorrStartHeight = math.MaxUint32 - p.VotesSchnorrStartHeight = math.MaxUint32 - p.MultiExchangeVotesStartHeight = math.MaxUint32 // todo complete me + p.ProducerSchnorrStartHeight = math.MaxUint32 // todo complete me + p.CRSchnorrStartHeight = math.MaxUint32 // todo complete me + p.VotesSchnorrStartHeight = math.MaxUint32 // todo complete me + p.MultiExchangeVotesStartHeight = 1171000 p.MemoryPoolTxMaximumStayHeight = 10 diff --git a/core/checkpoint/manager.go b/core/checkpoint/manager.go index d35087bd7..c9f70b0d3 100644 --- a/core/checkpoint/manager.go +++ b/core/checkpoint/manager.go @@ -113,6 +113,9 @@ type ICheckPoint interface { // GetHeight returns initial height checkpoint should start with. StartHeight() uint32 + + //reset + OnReset() error } // Manager holds checkpoints save automatically. @@ -203,6 +206,20 @@ func (m *Manager) GetCheckpoint(key string, height uint32) ( } } +func (m *Manager) OnReset() error { + m.mtx.Lock() + defer m.mtx.Unlock() + + sortedPoints := m.getOrderedCheckpoints() + for i, v := range sortedPoints { + err := v.OnReset() + if err != nil { + log.Error(" Reset ", err, " i", i) + } + } + return nil +} + // Restore will load all data of each checkpoints file and store in // corresponding meta-data. func (m *Manager) Restore() (err error) { diff --git a/core/checkpoint/manager_test.go b/core/checkpoint/manager_test.go index 28a979599..cfec3f09a 100644 --- a/core/checkpoint/manager_test.go +++ b/core/checkpoint/manager_test.go @@ -139,6 +139,10 @@ func (c *checkpoint) OnRollbackSeekTo(height uint32) { return } +func (c *checkpoint) OnReset() error { + return nil +} + func TestManager_SaveAndRestore(t *testing.T) { data := uint64(1) currentHeight := uint32(10) diff --git a/core/transaction/cancelproducertransaction.go b/core/transaction/cancelproducertransaction.go index b9e079394..eee934950 100644 --- a/core/transaction/cancelproducertransaction.go +++ b/core/transaction/cancelproducertransaction.go @@ -65,7 +65,7 @@ func (t *CancelProducerTransaction) SpecialContextCheck() (elaerr.ELAError, bool return elaerr.Simple(elaerr.ErrTxPayload, errors.New("can not cancel DPoS V1&V2 producer")), true } } - + //need return Returned if producer.State() == state.Illegal || producer.State() == state.Canceled { return elaerr.Simple(elaerr.ErrTxPayload, errors.New("can not cancel this producer")), true diff --git a/core/transaction/crcouncilmemberclaimnodetransaction.go b/core/transaction/crcouncilmemberclaimnodetransaction.go index fcdd77430..62653ec0b 100644 --- a/core/transaction/crcouncilmemberclaimnodetransaction.go +++ b/core/transaction/crcouncilmemberclaimnodetransaction.go @@ -10,8 +10,8 @@ import ( "encoding/hex" "errors" "fmt" - "github.com/elastos/Elastos.ELA/blockchain" + "github.com/elastos/Elastos.ELA/core/contract" "github.com/elastos/Elastos.ELA/core/types/payload" crstate "github.com/elastos/Elastos.ELA/cr/state" "github.com/elastos/Elastos.ELA/crypto" @@ -56,13 +56,31 @@ func (t *CRCouncilMemberClaimNodeTransaction) SpecialContextCheck() (result elae !t.parameters.BlockChain.GetCRCommittee().IsInElectionPeriod() { return elaerr.Simple(elaerr.ErrTxPayload, errors.New("CRCouncilMemberClaimNode must during election period")), true } + switch t.payloadVersion { + case payload.CurrentCRClaimDPoSNodeVersion, payload.NextCRClaimDPoSNodeVersion: + crMember := t.parameters.BlockChain.GetCRCommittee().GetMember(manager.CRCouncilCommitteeDID) + if crMember != nil && (!contract.IsStandard(crMember.Info.Code)) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("CurrentCRClaimDPoSNodeVersion or NextCRClaimDPoSNodeVersion match standard code")), true + } + case payload.CurrentCRClaimDPoSNodeMultiSignVersion, payload.NextCRClaimDPoSNodeMultiSignVersion: + if !contract.IsMultiSig(t.Programs()[0].Code) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("CurrentCRClaimDPoSNodeMultiSignVersion or NextCRClaimDPoSNodeMultiSignVersion match multi code")), true + } + programDID, err1 := getDIDFromCode(t.Programs()[0].Code) + if err1 != nil { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("can not create did from program code")), true + } + if !programDID.IsEqual(manager.CRCouncilCommitteeDID) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("program code not match with payload CRCouncilCommitteeDID")), true + } + } did := manager.CRCouncilCommitteeDID var crMember *crstate.CRMember comm := t.parameters.BlockChain.GetCRCommittee() if t.parameters.BlockHeight >= t.parameters.Config.DPoSV2StartHeight { switch t.payloadVersion { - case payload.CurrentCRClaimDPoSNodeVersion: + case payload.CurrentCRClaimDPoSNodeVersion, payload.CurrentCRClaimDPoSNodeMultiSignVersion: crMember = t.parameters.BlockChain.GetCRCommittee().GetMember(did) if _, ok := comm.ClaimedDPoSKeys[hex.EncodeToString(manager.NodePublicKey)]; ok { return elaerr.Simple(elaerr.ErrTxPayload, fmt.Errorf("producer already registered")), true @@ -71,7 +89,7 @@ func (t *CRCouncilMemberClaimNodeTransaction) SpecialContextCheck() (result elae if t.parameters.BlockChain.GetState().ProducerAndCurrentCRNodePublicKeyExists(manager.NodePublicKey) { return elaerr.Simple(elaerr.ErrTxPayload, fmt.Errorf("producer already registered")), true } - case payload.NextCRClaimDPoSNodeVersion: + case payload.NextCRClaimDPoSNodeVersion, payload.NextCRClaimDPoSNodeMultiSignVersion: crMember = t.parameters.BlockChain.GetCRCommittee().GetNextMember(did) if _, ok := comm.NextClaimedDPoSKeys[hex.EncodeToString(manager.NodePublicKey)]; ok { return elaerr.Simple(elaerr.ErrTxPayload, fmt.Errorf("producer already registered")), true @@ -103,9 +121,11 @@ func (t *CRCouncilMemberClaimNodeTransaction) SpecialContextCheck() (result elae return elaerr.Simple(elaerr.ErrTxPayload, errors.New("invalid operating public key")), true } - err = checkCRCouncilMemberClaimNodeSignature(manager, crMember.Info.Code) - if err != nil { - return elaerr.Simple(elaerr.ErrTxPayload, errors.New("CR claim DPOS signature check failed")), true + if t.payloadVersion < payload.CurrentCRClaimDPoSNodeMultiSignVersion { + err = checkCRCouncilMemberClaimNodeSignature(manager, crMember.Info.Code) + if err != nil { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("CR claim DPOS signature check failed")), true + } } return nil, false diff --git a/core/transaction/crcouncilmemberclaimnodetransaction_test.go b/core/transaction/crcouncilmemberclaimnodetransaction_test.go index 32c0e1041..ec87334d9 100644 --- a/core/transaction/crcouncilmemberclaimnodetransaction_test.go +++ b/core/transaction/crcouncilmemberclaimnodetransaction_test.go @@ -27,10 +27,14 @@ func (s *txValidatorTestSuite) TestCRCouncilMemberClaimNodeTransaction() { //publicKey2, _ := common.HexStringToBytes(publicKeyStr2) //errPublicKeyStr := "02b611f07341d5ddce51b5c4366aca7b889cfe0993bd63fd4" //errPublicKey, _ := common.HexStringToBytes(errPublicKeyStr) - did := randomUint168() + //did := randomUint168() + code := getCodeByPubKeyStr(publicKeyStr1) + did, _ := getDIDFromCode(code) + { claimPayload := &payload.CRCouncilMemberClaimNode{ - NodePublicKey: publicKey1, + NodePublicKey: publicKey1, + CRCouncilCommitteeDID: *did, } programs := []*program.Program{{ @@ -81,7 +85,8 @@ func (s *txValidatorTestSuite) TestCRCouncilMemberClaimNodeTransaction() { { claimPayload := &payload.CRCouncilMemberClaimNode{ - NodePublicKey: publicKey1, + NodePublicKey: publicKey1, + CRCouncilCommitteeDID: *did, } programs := []*program.Program{{ @@ -113,6 +118,9 @@ func (s *txValidatorTestSuite) TestCRCouncilMemberClaimNodeTransaction() { "transaction validate error: payload content invalid:producer already registered") s.Chain.GetCRCommittee().NextMembers[*did] = &state.CRMember{ + Info: payload.CRInfo{ + DID: *did, + }, MemberState: state.MemberIllegal, } s.Chain.GetCRCommittee().NextClaimedDPoSKeys = make(map[string]struct{}, 0) @@ -122,6 +130,9 @@ func (s *txValidatorTestSuite) TestCRCouncilMemberClaimNodeTransaction() { "transaction validate error: payload content invalid:CR Council Member should be an elected or inactive CR members") s.Chain.GetCRCommittee().NextMembers[*did] = &state.CRMember{ + Info: payload.CRInfo{ + DID: *did, + }, MemberState: state.MemberElected, DPOSPublicKey: publicKey1, } @@ -130,7 +141,8 @@ func (s *txValidatorTestSuite) TestCRCouncilMemberClaimNodeTransaction() { "transaction validate error: payload content invalid:NodePublicKey is the same as crMember.DPOSPublicKey") claimPayload = &payload.CRCouncilMemberClaimNode{ - NodePublicKey: randomBytes(22), + NodePublicKey: randomBytes(22), + CRCouncilCommitteeDID: *did, } txn.SetPayload(claimPayload) err, _ = txn.SpecialContextCheck() @@ -143,10 +155,12 @@ func (s *txValidatorTestSuite) TestCRCouncilMemberClaimNodeTransaction() { DPOSPublicKey: randomBytes(32), Info: payload.CRInfo{ Code: code, + DID: *did, }, } claimPayload = &payload.CRCouncilMemberClaimNode{ - NodePublicKey: publicKey1, + NodePublicKey: publicKey1, + CRCouncilCommitteeDID: *did, } buf := new(bytes.Buffer) claimPayload.SerializeUnsigned(buf, 0) diff --git a/core/transaction/crcproposaltransaction.go b/core/transaction/crcproposaltransaction.go index 94f179c10..3b2f0f0c5 100644 --- a/core/transaction/crcproposaltransaction.go +++ b/core/transaction/crcproposaltransaction.go @@ -92,6 +92,17 @@ func (t *CRCProposalTransaction) SpecialContextCheck() (result elaerr.ELAError, if t.parameters.BlockChain.GetCRCommittee().IsProposalFull(proposal.CRCouncilMemberDID) { return elaerr.Simple(elaerr.ErrTxPayload, errors.New("proposal is full")), true } + + if len(proposal.OwnerKey) != 0 && len(proposal.OwnerKey) != 33 { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("OwnerKey must standard publickey")), true + } + if len(proposal.NewOwnerKey) != 0 && len(proposal.NewOwnerKey) != 33 { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("NewOwnerKey must standard publickey")), true + } + if len(proposal.SecretaryGeneralPublicKey) != 0 && len(proposal.SecretaryGeneralPublicKey) != 33 { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("SecretaryGeneralPublicKey must standard publickey")), true + } + // Check draft hash of proposal. if t.parameters.BlockChain.GetCRCommittee().ExistDraft(proposal.DraftHash) { return elaerr.Simple(elaerr.ErrTxPayload, errors.New("duplicated draft proposal hash")), true diff --git a/core/transaction/registercrtransaction.go b/core/transaction/registercrtransaction.go index b4369fc94..ab8cd2003 100644 --- a/core/transaction/registercrtransaction.go +++ b/core/transaction/registercrtransaction.go @@ -8,12 +8,12 @@ package transaction import ( "errors" "fmt" - "github.com/elastos/Elastos.ELA/blockchain" "github.com/elastos/Elastos.ELA/common" "github.com/elastos/Elastos.ELA/core/contract" "github.com/elastos/Elastos.ELA/core/types/payload" crstate "github.com/elastos/Elastos.ELA/cr/state" + "github.com/elastos/Elastos.ELA/crypto" elaerr "github.com/elastos/Elastos.ELA/errors" "github.com/elastos/Elastos.ELA/vm" ) @@ -55,6 +55,11 @@ func (t *RegisterCRTransaction) HeightVersionCheck() error { return errors.New(fmt.Sprintf("not support %s transaction "+ "before CRSchnorrStartHeight", t.TxType().Name())) } + case payload.CRInfoMultiSignVersion: + if blockHeight < chainParams.DPoSConfiguration.ChangeViewV1Height { + return errors.New(fmt.Sprintf("not support %s transaction CRInfoMultiSignVersion"+ + "before ChangeViewV1Height", t.TxType().Name())) + } default: return errors.New(fmt.Sprintf("invalid payload version, "+ "%s transaction", t.TxType().Name())) @@ -82,6 +87,28 @@ func (t *RegisterCRTransaction) SpecialContextCheck() (elaerr.ELAError, bool) { return elaerr.Simple(elaerr.ErrTxPayload, err), true } + switch t.payloadVersion { + case payload.CRInfoVersion, payload.CRInfoDIDVersion: + if !contract.IsStandard(t.Programs()[0].Code) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("CRInfoVersion or CRInfoDIDVersion match standard code")), true + } + case payload.CRInfoSchnorrVersion: + if !contract.IsSchnorr(t.Programs()[0].Code) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New(" CRInfoSchnorrVersion match schnorr code")), true + } + case payload.CRInfoMultiSignVersion: + if !contract.IsMultiSig(t.Programs()[0].Code) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("CRInfoMultiSignVersion match multi code")), true + } + //check n + code := t.Programs()[0].Code + n := int(code[len(code)-2]) - crypto.PUSH1 + 1 + if n > MaxMultisignN { + return elaerr.Simple(elaerr.ErrTxPayload, + errors.New("RegisterCRTransaction multisign n can not over 10")), true + } + } + // check url if err := checkStringField(info.Url, "Url", true); err != nil { return elaerr.Simple(elaerr.ErrTxPayload, err), true @@ -97,7 +124,8 @@ func (t *RegisterCRTransaction) SpecialContextCheck() (elaerr.ELAError, bool) { cr := t.parameters.BlockChain.GetCRCommittee().GetCandidate(info.CID) if cr != nil { - return elaerr.Simple(elaerr.ErrTxPayload, fmt.Errorf("cid %s already exist", info.CID)), true + cidAddr, _ := info.CID.ToAddress() + return elaerr.Simple(elaerr.ErrTxPayload, fmt.Errorf("cid %s already exist", cidAddr)), true } // get CID program hash and check length of code @@ -142,7 +170,7 @@ func (t *RegisterCRTransaction) SpecialContextCheck() (elaerr.ELAError, bool) { } if t.parameters.BlockHeight >= t.parameters.Config.CRConfiguration.RegisterCRByDIDHeight && - t.PayloadVersion() == payload.CRInfoDIDVersion { + t.PayloadVersion() >= payload.CRInfoDIDVersion { // get DID program hash programHash, err = getDIDFromCode(code) diff --git a/core/transaction/registercrtransaction_test.go b/core/transaction/registercrtransaction_test.go index 5718b6a5f..c964fcb52 100644 --- a/core/transaction/registercrtransaction_test.go +++ b/core/transaction/registercrtransaction_test.go @@ -142,7 +142,8 @@ func (s *txValidatorTestSuite) TestCheckRegisterCRTransaction() { s.Chain.GetCRCommittee().GetState().CodeCIDMap[codeStr1] = *cid1 s.Chain.GetCRCommittee().GetState().Candidates[*cid1] = &crstate.Candidate{} err, _ = txn.SpecialContextCheck() - s.EqualError(err, "transaction validate error: payload content invalid:cid "+cid1.String()+" already exist") + cid1Addr, _ := cid1.ToAddress() + s.EqualError(err, "transaction validate error: payload content invalid:cid "+cid1Addr+" already exist") delete(s.Chain.GetCRCommittee().GetState().Candidates, *cid1) // Give an invalid code in payload @@ -227,35 +228,7 @@ func (s *txValidatorTestSuite) TestCheckRegisterCRTransaction() { BlockChain: s.Chain, }) err, _ = txn.SpecialContextCheck() - s.EqualError(err, "transaction validate error: payload content invalid:CR not support multi sign code") - - txn = s.getMultiSigRegisterCRTx( - []string{publicKeyStr1, publicKeyStr2, publicKeyStr3}, - []string{privateKeyStr1, privateKeyStr2}, nickName1) - txn = CreateTransactionByType(txn, s.Chain) - txn.SetParameters(&TransactionParameters{ - Transaction: txn, - BlockHeight: votingHeight, - TimeStamp: s.Chain.BestChain.Timestamp, - Config: s.Chain.GetParams(), - BlockChain: s.Chain, - }) - err, _ = txn.SpecialContextCheck() - s.EqualError(err, "transaction validate error: payload content invalid:CR not support multi sign code") - - txn = s.getMultiSigRegisterCRTx( - []string{publicKeyStr1, publicKeyStr2, publicKeyStr3}, - []string{privateKeyStr1}, nickName1) - txn = CreateTransactionByType(txn, s.Chain) - txn.SetParameters(&TransactionParameters{ - Transaction: txn, - BlockHeight: votingHeight, - TimeStamp: s.Chain.BestChain.Timestamp, - Config: s.Chain.GetParams(), - BlockChain: s.Chain, - }) - err, _ = txn.SpecialContextCheck() - s.EqualError(err, "transaction validate error: payload content invalid:CR not support multi sign code") + s.EqualError(err, "transaction validate error: payload content invalid:CRInfoVersion or CRInfoDIDVersion match standard code") //check register cr with CRInfoDIDVersion txn2 := s.getRegisterCRTx(publicKeyStr1, privateKeyStr1, nickName1, diff --git a/core/transaction/unregistercrtransaction.go b/core/transaction/unregistercrtransaction.go index 7456644f8..1f52c9540 100644 --- a/core/transaction/unregistercrtransaction.go +++ b/core/transaction/unregistercrtransaction.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "github.com/elastos/Elastos.ELA/blockchain" + "github.com/elastos/Elastos.ELA/core/contract" "github.com/elastos/Elastos.ELA/core/types/payload" crstate "github.com/elastos/Elastos.ELA/cr/state" elaerr "github.com/elastos/Elastos.ELA/errors" @@ -54,6 +55,21 @@ func (t *UnregisterCRTransaction) SpecialContextCheck() (elaerr.ELAError, bool) return elaerr.Simple(elaerr.ErrTxPayload, errors.New("should create tx during voting period")), true } + switch t.payloadVersion { + case payload.UnregisterCRVersion: + if !contract.IsStandard(t.Programs()[0].Code) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("UnregisterCRTransaction UnregisterCRVersion match standard code")), true + } + case payload.UnregisterCRSchnorrVersion: + if !contract.IsSchnorr(t.Programs()[0].Code) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("UnregisterCRTransaction UnregisterCRSchnorrVersion match schnorr code")), true + } + case payload.UnregisterCRMultiVersion: + if !contract.IsMultiSig(t.Programs()[0].Code) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("UnregisterCRTransaction UnregisterCRMultiVersion match multi code")), true + } + } + cr := t.parameters.BlockChain.GetCRCommittee().GetCandidate(info.CID) if cr == nil { return elaerr.Simple(elaerr.ErrTxPayload, errors.New("unregister unknown CR")), true diff --git a/core/transaction/updatecrtransaction.go b/core/transaction/updatecrtransaction.go index c94db59d3..4a61a6ea5 100644 --- a/core/transaction/updatecrtransaction.go +++ b/core/transaction/updatecrtransaction.go @@ -49,6 +49,21 @@ func (t *UpdateCRTransaction) SpecialContextCheck() (elaerr.ELAError, bool) { return elaerr.Simple(elaerr.ErrTxPayload, err), true } + switch t.payloadVersion { + case payload.CRInfoVersion, payload.CRInfoDIDVersion: + if !contract.IsStandard(t.Programs()[0].Code) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("CRInfoVersion or CRInfoDIDVersion match standard code")), true + } + case payload.CRInfoSchnorrVersion: + if !contract.IsSchnorr(t.Programs()[0].Code) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New(" CRInfoSchnorrVersion match schnorr code")), true + } + case payload.CRInfoMultiSignVersion: + if !contract.IsMultiSig(t.Programs()[0].Code) { + return elaerr.Simple(elaerr.ErrTxPayload, errors.New("CRInfoMultiSignVersion match multi code")), true + } + } + var code []byte if t.payloadVersion == payload.CRInfoSchnorrVersion || t.payloadVersion == payload.CRInfoMultiSignVersion { @@ -70,7 +85,7 @@ func (t *UpdateCRTransaction) SpecialContextCheck() (elaerr.ELAError, bool) { } if t.parameters.BlockHeight >= t.parameters.Config.CRConfiguration.RegisterCRByDIDHeight && - t.PayloadVersion() == payload.CRInfoDIDVersion { + t.PayloadVersion() >= payload.CRInfoDIDVersion { // get DID program hash programHash, err = getDIDFromCode(code) diff --git a/core/transaction/updateproducertransaction.go b/core/transaction/updateproducertransaction.go index c6fb9e4cd..727772c8f 100644 --- a/core/transaction/updateproducertransaction.go +++ b/core/transaction/updateproducertransaction.go @@ -250,7 +250,8 @@ func (t *UpdateProducerTransaction) additionalProducerInfoCheck(info *payload.Pr if bytes.Equal(m.DPOSPublicKey, info.NodePublicKey) { return errors.New("node public key can't equal with current CR Node PK") } - if bytes.Equal(m.Info.Code[1:len(m.Info.Code)-1], info.NodePublicKey) { + ownerKey := common.GetOwnerKey(m.Info.Code) + if bytes.Equal(ownerKey, info.NodePublicKey) { return errors.New("node public key can't equal with current CR Owner PK") } } @@ -259,7 +260,8 @@ func (t *UpdateProducerTransaction) additionalProducerInfoCheck(info *payload.Pr if bytes.Equal(m.DPOSPublicKey, info.NodePublicKey) { return errors.New("node public key can't equal with next CR Node PK") } - if bytes.Equal(m.Info.Code[1:len(m.Info.Code)-1], info.NodePublicKey) { + ownerKey := common.GetOwnerKey(m.Info.Code) + if bytes.Equal(ownerKey, info.NodePublicKey) { return errors.New("node public key can't equal with current CR Owner PK") } } diff --git a/core/types/payload/crcproposal.go b/core/types/payload/crcproposal.go index b8a184313..48953a347 100644 --- a/core/types/payload/crcproposal.go +++ b/core/types/payload/crcproposal.go @@ -1208,7 +1208,7 @@ func (p *CRCProposal) DeserializeNormalOrELIP(r io.Reader, version byte) error { return errors.New("failed to deserialize CRCouncilMemberDID") } - CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.SignatureLength, "CR sign data") + CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.MaxSignatureScriptLength, "CR sign data") if err != nil { return err } @@ -1233,7 +1233,7 @@ func (p *CRCProposal) DeserializeUpgradeCode(r io.Reader, version byte) error { return errors.New("failed to deserialize CRCouncilMemberDID") } // cr signature - CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.SignatureLength, "CR sign data") + CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.MaxSignatureScriptLength, "CR sign data") if err != nil { return err } @@ -1264,7 +1264,7 @@ func (p *CRCProposal) DeserializeChangeProposalOwner(r io.Reader, version byte) return errors.New("failed to deserialize CRCouncilMemberDID") } // cr signature - CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.SignatureLength, "CR sign data") + CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.MaxSignatureScriptLength, "CR sign data") if err != nil { return err } @@ -1286,7 +1286,7 @@ func (p *CRCProposal) DeserializeRegisterSideChain(r io.Reader, version byte) er return errors.New("failed to deserialize CRCouncilMemberDID") } - CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.SignatureLength, "CR sign data") + CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.MaxSignatureScriptLength, "CR sign data") if err != nil { return err } @@ -1311,7 +1311,7 @@ func (p *CRCProposal) DeserializeCloseProposal(r io.Reader, version byte) error return errors.New("failed to deserialize CRCouncilMemberDID") } - CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.SignatureLength, "CR sign data") + CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.MaxSignatureScriptLength, "CR sign data") if err != nil { return err } @@ -1342,7 +1342,7 @@ func (p *CRCProposal) DeserializeChangeSecretaryGeneral(r io.Reader, version byt return errors.New("failed to deserialize CRCouncilMemberDID") } - CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.SignatureLength, "CR sign data") + CRCouncilMemberSignature, err := common.ReadVarBytes(r, crypto.MaxSignatureScriptLength, "CR sign data") if err != nil { return err } diff --git a/core/types/payload/crdposmanagement.go b/core/types/payload/crdposmanagement.go index 8590bb2c9..51e589859 100644 --- a/core/types/payload/crdposmanagement.go +++ b/core/types/payload/crdposmanagement.go @@ -11,6 +11,8 @@ import ( const CurrentCRClaimDPoSNodeVersion byte = 0x00 const NextCRClaimDPoSNodeVersion byte = 0x01 +const CurrentCRClaimDPoSNodeMultiSignVersion byte = 0x02 +const NextCRClaimDPoSNodeMultiSignVersion byte = 0x03 type CRCouncilMemberClaimNode struct { NodePublicKey []byte @@ -31,10 +33,12 @@ func (p *CRCouncilMemberClaimNode) Serialize(w io.Writer, version byte) error { if err != nil { return err } - - if err := common.WriteVarBytes(w, p.CRCouncilCommitteeSignature); err != nil { - return errors.New("Serialize error") + if version < CurrentCRClaimDPoSNodeMultiSignVersion { + if err := common.WriteVarBytes(w, p.CRCouncilCommitteeSignature); err != nil { + return errors.New("Serialize error") + } } + return nil } @@ -53,10 +57,13 @@ func (p *CRCouncilMemberClaimNode) Deserialize(r io.Reader, version byte) error if err != nil { return err } - p.CRCouncilCommitteeSignature, err = common.ReadVarBytes(r, crypto.MaxSignatureScriptLength, "signature") - if err != nil { - return errors.New("Deserialize error") + if version < CurrentCRClaimDPoSNodeMultiSignVersion { + p.CRCouncilCommitteeSignature, err = common.ReadVarBytes(r, crypto.MaxSignatureScriptLength, "signature") + if err != nil { + return errors.New("Deserialize error") + } } + return nil } diff --git a/cr/state/checkpoint.go b/cr/state/checkpoint.go index 39a92f6d8..b6a72b33f 100644 --- a/cr/state/checkpoint.go +++ b/cr/state/checkpoint.go @@ -46,6 +46,27 @@ func (c *Checkpoint) OnBlockSaved(block *types.DposBlock) { c.committee.ProcessBlock(block.Block, block.Confirm) } +func (c *Checkpoint) OnReset() error { + log.Info("cr state OnReset") + keyFrame := NewKeyFrame() + + committee := &Committee{ + state: NewState(c.committee.Params), + Params: c.committee.Params, + KeyFrame: *keyFrame, + firstHistory: utils.NewHistory(maxHistoryCapacity), + inactiveCRHistory: utils.NewHistory(maxHistoryCapacity), + committeeHistory: utils.NewHistory(maxHistoryCapacity), + appropriationHistory: utils.NewHistory(maxHistoryCapacity), + } + c.initFromCommittee(committee) + c.committee.Recover(c) + c.committee.state.RegisterFunctions(&FunctionsConfig{ + GetHistoryMember: committee.getHistoryMember, + }) + return nil +} + func (c *Checkpoint) OnRollbackTo(height uint32) error { keyFrame := NewKeyFrame() if height < c.StartHeight() { diff --git a/cr/state/committee.go b/cr/state/committee.go index 7ca7b5fc0..325276566 100644 --- a/cr/state/committee.go +++ b/cr/state/committee.go @@ -235,7 +235,7 @@ func (c *Committee) GetNextMembers() []*CRMember { return result } -// get CRMember ordered by owner public key +// get CRMember ordered by owner key func (c *Committee) GetCRMember(key string) *CRMember { c.mtx.RLock() defer c.mtx.RUnlock() @@ -243,7 +243,9 @@ func (c *Committee) GetCRMember(key string) *CRMember { result := getCRMembers(c.Members) for _, cr := range result { - if hex.EncodeToString(cr.Info.Code[1:len(cr.Info.Code)-1]) == key { + //ownerKey + ownerKey := common.GetOwnerKey(cr.Info.Code) + if hex.EncodeToString(ownerKey) == key { return cr } } @@ -251,7 +253,8 @@ func (c *Committee) GetCRMember(key string) *CRMember { result = getCRMembers(c.NextMembers) for _, cr := range result { - if hex.EncodeToString(cr.Info.Code[1:len(cr.Info.Code)-1]) == key { + ownerKey := common.GetOwnerKey(cr.Info.Code) + if hex.EncodeToString(ownerKey) == key { return cr } } @@ -384,7 +387,7 @@ func (c *Committee) updateVotingCandidatesState(height uint32) { // Check if any pending candidates has got 6 confirms, set them to activate. activateCandidateFromPending := func(key common.Uint168, candidate *Candidate) { - c.state.History.Append(height, func() { + c.committeeHistory.Append(height, func() { candidate.State = Active c.state.Candidates[key] = candidate }, func() { @@ -438,11 +441,11 @@ func (c *Committee) ProcessBlock(block *types.Block, confirm *payload.Confirm) { c.recordLastVotingStartHeight(block.Height) c.processTransactions(block.Transactions, block.Height) - c.updateVotingCandidatesState(block.Height) c.updateCandidatesDepositCoin(block.Height) c.state.History.Commit(block.Height) inElectionPeriod := c.tryStartVotingPeriod(block.Height) + c.updateVotingCandidatesState(block.Height) c.updateProposals(block.Height, inElectionPeriod) c.updateCirculationAmount(c.committeeHistory, block.Height) @@ -510,6 +513,7 @@ func (c *Committee) checkAndSetMemberToInactive(history *utils.History, height u c.state.UpdateCRInactivePenalty(m.Info.CID, height) } }, func() { + //todo revert m.MemberState = MemberElected if height >= c.Params.CRConfiguration.ChangeCommitteeNewCRHeight { c.state.RevertUpdateCRInactivePenalty(m.Info.CID, height) @@ -626,6 +630,7 @@ func (c *Committee) transferCRMemberState(crMember *CRMember, height uint32) { oriMemberState := crMember.MemberState penalty := c.getMemberPenalty(height, crMember, true) c.committeeHistory.Append(height, func() { + //here is also before processtransaction history commit crMember.MemberState = MemberImpeached c.state.DepositInfo[crMember.Info.CID].Penalty = penalty c.state.DepositInfo[crMember.Info.CID].DepositAmount -= MinDepositAmount @@ -1185,6 +1190,7 @@ func (c *Committee) getSignersFromWithdrawFromSideChainTx(tx interfaces.Transact publicKeys := make([]string, 0) if tx.PayloadVersion() == payload.WithdrawFromSideChainVersionV2 { allPulicKeys := c.getCurrentArbiters() + pld := tx.Payload().(*payload.WithdrawFromSideChain) for _, index := range pld.Signers { publicKeys = append(publicKeys, hex.EncodeToString(allPulicKeys[index])) @@ -1235,7 +1241,7 @@ func (c *Committee) processCRCouncilMemberClaimNode(tx interfaces.Transaction, var cr *CRMember if height >= c.Params.DPoSV2StartHeight { switch tx.PayloadVersion() { - case payload.CurrentCRClaimDPoSNodeVersion: + case payload.CurrentCRClaimDPoSNodeVersion, payload.CurrentCRClaimDPoSNodeMultiSignVersion: cr = c.getMember(claimNodePayload.CRCouncilCommitteeDID) if cr == nil { return @@ -1249,7 +1255,7 @@ func (c *Committee) processCRCouncilMemberClaimNode(tx interfaces.Transaction, }, func() { c.ClaimedDPoSKeys = oriClaimDPoSKeys }) - case payload.NextCRClaimDPoSNodeVersion: + case payload.NextCRClaimDPoSNodeVersion, payload.NextCRClaimDPoSNodeMultiSignVersion: cr = c.getNextMember(claimNodePayload.CRCouncilCommitteeDID) if cr == nil { return diff --git a/cr/state/committeeaction.go b/cr/state/committeeaction.go index 90418cb8f..70a201fd2 100644 --- a/cr/state/committeeaction.go +++ b/cr/state/committeeaction.go @@ -37,15 +37,21 @@ func (c *Committee) processTransactions(txs []interfaces.Transaction, height uin } c.checkWithdrawAndInactiveCR(sortedTxs[1:], height) - // Check if any pending inactive CR member has got 6 confirms, then set them // to elected. activateCRMemberFromInactive := func(cr *CRMember) { oriState := cr.MemberState oriActivateRequestHeight := cr.ActivateRequestHeight c.state.History.Append(height, func() { - cr.MemberState = MemberElected + //At first MemberState is MemberInactive or MemberIllegal + //CRCouncilMemberClaimNode MemberInactive->MemberElected + //CRCouncilMemberClaimNode may confilct with ActivateProducer + if canChangeState(cr.MemberState, MemberElected) { + cr.MemberState = MemberElected + } + //in case of more call of activateCRMemberFromInactive cr.ActivateRequestHeight = math.MaxUint32 + }, func() { cr.MemberState = oriState cr.ActivateRequestHeight = oriActivateRequestHeight @@ -64,6 +70,45 @@ func (c *Committee) processTransactions(txs []interfaces.Transaction, height uin } } +/* +transaction effect statue is + MemberInactive by tx CRCouncilMemberClaimNode ---》 MemberElected + by tx ReturnCRDepositCoin --》MemberReturned +*/ + +// MemberElected MemberImpeached MemberTerminated MemberReturned MemberInactive MemberIllegal +// MemberIllegal MemberInactive change is in dpos state +func canChangeState(nowState, targetState MemberState) bool { + switch targetState { + case MemberElected: + if nowState != MemberInactive && nowState != MemberIllegal { + return false + } else { + return true + } + case MemberInactive: //first is MemberElected,then + //only MemberElected + if nowState != MemberElected { + return false + } else { + return true + } + case MemberImpeached: + if nowState != MemberElected && nowState != MemberInactive && nowState != MemberIllegal { + return false + } else { + return true + } + case MemberTerminated: + if nowState != MemberElected && nowState != MemberInactive && nowState != MemberIllegal { + return false + } else { + return true + } + } + return false +} + // SortTransactions purpose is to process some transaction first. func SortTransactions(txs []interfaces.Transaction) { sort.Slice(txs, func(i, j int) bool { @@ -137,12 +182,19 @@ func (c *Committee) inactiveMembersByWithdrawKeys(height uint32, if _, ok := wmap[hex.EncodeToString(m.DPOSPublicKey)]; !ok { // inactive CR member c.state.History.Append(height, func() { - member.MemberState = MemberInactive - log.Infof("[checkWithdrawAndInactiveCR] Set %s to inactive", member.Info.NickName) - if height >= c.Params.CRConfiguration.ChangeCommitteeNewCRHeight { - c.state.UpdateCRInactivePenalty(member.Info.CID, height) + //here should becarefull. this is before processtransaction history commit, MemberState may change since tx + //MemberImpeached, MemberTerminated, MemberReturned MemberIllegal MemberElected + changeState := canChangeState(member.MemberState, MemberInactive) + if changeState { + member.MemberState = MemberInactive + log.Infof("[checkWithdrawAndInactiveCR] Set %s to inactive", member.Info.NickName) + if height >= c.Params.CRConfiguration.ChangeCommitteeNewCRHeight { + c.state.UpdateCRInactivePenalty(member.Info.CID, height) + } } + }, func() { + //todo member.MemberState = MemberElected if height >= c.Params.CRConfiguration.ChangeCommitteeNewCRHeight { c.state.RevertUpdateCRInactivePenalty(member.Info.CID, height) diff --git a/cr/state/state.go b/cr/state/state.go index 418f0c088..8f9e918fb 100644 --- a/cr/state/state.go +++ b/cr/state/state.go @@ -8,7 +8,6 @@ package state import ( "encoding/hex" "errors" - "github.com/elastos/Elastos.ELA/common" "github.com/elastos/Elastos.ELA/common/config" "github.com/elastos/Elastos.ELA/core/contract" @@ -344,8 +343,11 @@ func (s *State) updateCandidateInfo(origin *payload.CRInfo, update *payload.CRIn delete(s.Nicknames, origin.NickName) s.Nicknames[update.NickName] = struct{}{} } - + originCode := candidate.Info.Code candidate.Info = *update + if len(originCode) != 0 && update.Code == nil { + candidate.Info.Code = originCode + } } // processDeposit takes a transaction output with deposit program hash. diff --git a/dpos/arbitrator.go b/dpos/arbitrator.go index 92a3851a6..b13695dcc 100644 --- a/dpos/arbitrator.go +++ b/dpos/arbitrator.go @@ -289,7 +289,7 @@ func NewArbitrator(account account.Account, cfg Config) (*Arbitrator, error) { consensus := manager.NewConsensus(dposManager, cfg.ChainParams.DPoSConfiguration.SignTolerance, - dposHandlerSwitch, cfg.ChainParams.DPoSConfiguration.ChangeViewV1Height) + dposHandlerSwitch, cfg.ChainParams.DPoSConfiguration.ChangeViewV1Height, cfg.Chain.BestChain.Height) proposalDispatcher, illegalMonitor := manager.NewDispatcherAndIllegalMonitor( manager.ProposalDispatcherConfig{ EventMonitor: eventMonitor, @@ -302,6 +302,7 @@ func NewArbitrator(account account.Account, cfg Config) (*Arbitrator, error) { EventAnalyzerConfig: manager.EventAnalyzerConfig{ Arbitrators: cfg.Arbitrators, }, + BestHeight: cfg.Chain.BestChain.Height, }) dposHandlerSwitch.Initialize(proposalDispatcher, consensus) diff --git a/dpos/manager/consensus.go b/dpos/manager/consensus.go index b2e9143da..f75993757 100644 --- a/dpos/manager/consensus.go +++ b/dpos/manager/consensus.go @@ -32,7 +32,7 @@ type Consensus struct { } func NewConsensus(manager *DPOSManager, tolerance time.Duration, - viewListener ViewListener, changeViewV1Height uint32) *Consensus { + viewListener ViewListener, changeViewV1Height, bestHeight uint32) *Consensus { c := &Consensus{ consensusStatus: consensusReady, viewOffset: DefaultViewOffset, @@ -44,6 +44,7 @@ func NewConsensus(manager *DPOSManager, tolerance time.Duration, arbitrators: manager.arbitrators, changeViewV1Height: changeViewV1Height, }, + finishedHeight: bestHeight, } return c @@ -109,6 +110,7 @@ func (c *Consensus) GetViewOffset() uint32 { } func (c *Consensus) ProcessBlock(b *types.Block) { + c.manager.GetBlockCache().AddValue(b.Hash(), b) } @@ -123,6 +125,8 @@ func (c *Consensus) ChangeView() { func (c *Consensus) TryChangeView() bool { if c.IsRunning() { + log.Warn("TryChangeView finishedHeight ", c.finishedHeight) + log.Warn("TryChangeView ChangeViewV1Height ", c.manager.chainParams.DPoSConfiguration.ChangeViewV1Height) if c.finishedHeight < c.manager.chainParams.DPoSConfiguration.ChangeViewV1Height { return c.currentView.TryChangeView(&c.viewOffset, c.manager.timeSource.AdjustedTime()) } else { diff --git a/dpos/manager/dposmanager.go b/dpos/manager/dposmanager.go index 4863bce4a..9262220cd 100644 --- a/dpos/manager/dposmanager.go +++ b/dpos/manager/dposmanager.go @@ -159,6 +159,7 @@ func NewManager(cfg DPOSManagerConfig) *DPOSManager { statusMap: make(map[uint32]map[string]*dmsg.ConsensusStatus), requestedBlocks: make(map[common.Uint256]struct{}), } + m.blockCache.Reset(nil) return m @@ -301,6 +302,8 @@ func (d *DPOSManager) OnBlock(id dpeer.PID, block *types.Block) { } delete(d.requestedBlocks, hash) if block.Header.Height == blockchain.DefaultLedger.Blockchain.GetHeight()+1 { + log.Debug("[OnBlock] before AppendDposBlock:", block.Hash().String()) + if _, _, err := d.blockPool.AppendDposBlock(&types.DposBlock{ Block: block, }); err != nil { @@ -503,7 +506,7 @@ func medianOf(nums []int64) int64 { func (d *DPOSManager) OnChangeView() { if d.consensus.TryChangeView() { - log.Info("[TryChangeView] succeed") + log.Info("[TryChangeView] succeed 3") } if d.consensus.viewOffset >= maxViewOffset { @@ -564,8 +567,12 @@ func (d *DPOSManager) OnBlockReceived(b *types.Block, confirmed bool) { } } + defer log.Info("####[OnBlockReceived] b.Hash()", b.Hash()) + if b.Height > blockchain.DefaultLedger.Blockchain.GetHeight() && b.Height > d.dispatcher.GetFinishedHeight() { //new height block coming + defer log.Info("####[OnBlockReceived] before ProcessHigherBlock b.Hash()", b.Hash()) + d.ProcessHigherBlock(b) } else { log.Warn("a.Leger.LastBlock.Height", blockchain.DefaultLedger.Blockchain.GetHeight(), "b.Height", b.Height) diff --git a/dpos/manager/dposnormalhandler.go b/dpos/manager/dposnormalhandler.go index b9f7da47a..95f178650 100644 --- a/dpos/manager/dposnormalhandler.go +++ b/dpos/manager/dposnormalhandler.go @@ -85,14 +85,10 @@ func (h *DPOSNormalHandler) ProcessProposal(id peer.PID, p *payload.DPOSProposal } func (h *DPOSNormalHandler) ChangeView(firstBlockHash *common.Uint256) { - log.Info("[OnViewChanged] clean proposal") + log.Info("[ChangeView] begin len precociousProposals", len(h.proposalDispatcher.precociousProposals)) h.proposalDispatcher.CleanProposals(true) - // sign proposal with same view offset to me - for _, v := range h.proposalDispatcher.precociousProposals { - if h.consensus.GetViewOffset() == v.ViewOffset { - h.proposalDispatcher.ProcessProposal(peer.PID{}, v, false) - } - } + log.Info("[ChangeView] end") + } func (h *DPOSNormalHandler) TryStartNewConsensus(b *types.Block) bool { diff --git a/dpos/manager/proposaldispatcher.go b/dpos/manager/proposaldispatcher.go index f7223b098..f95a2a7ed 100644 --- a/dpos/manager/proposaldispatcher.go +++ b/dpos/manager/proposaldispatcher.go @@ -40,6 +40,7 @@ type ProposalDispatcherConfig struct { Account account.Account ChainParams *config.Configuration TimeSource dtime.MedianTimeSource + BestHeight uint32 } type ProposalDispatcher struct { @@ -221,6 +222,7 @@ func (p *ProposalDispatcher) CleanProposals(changeView bool) { p.signedTxs = map[common.Uint256]interface{}{} p.pendingProposals = make(map[common.Uint256]*payload.DPOSProposal) p.precociousProposals = make(map[common.Uint256]*payload.DPOSProposal) + log.Info("Clean proposals precociousProposals clear") p.eventAnalyzer.Clear() } else { @@ -326,7 +328,6 @@ func (p *ProposalDispatcher) ProcessProposal(id peer.PID, d *payload.DPOSProposa if !ok || !p.cfg.Consensus.IsRunning() { p.pendingProposals[d.Hash()] = d p.cfg.Manager.OnInv(id, d.BlockHash) - log.Info("received pending proposal") return true, true } else { p.TryStartSpeculatingProposal(currentBlock) @@ -385,7 +386,7 @@ func (p *ProposalDispatcher) UpdatePrecociousProposals() { if p.cfg.Consensus.IsRunning() && v.ViewOffset == p.cfg.Consensus.GetViewOffset() { if needRecord, _ := p.ProcessProposal( - peer.PID{}, v, true); needRecord { + peer.PID(v.Sponsor), v, true); needRecord { p.illegalMonitor.AddProposal(v) } delete(p.precociousProposals, k) @@ -802,6 +803,7 @@ func (p *ProposalDispatcher) countAcceptedVote(v *payload.DPOSProposalVote) ( if v.Accept { log.Info("[countAcceptedVote] Received needed sign, collect it into AcceptVotes!") p.acceptVotes[v.Hash()] = v + log.Infof("[countAcceptedVote] Received needed sign, collect it into AcceptVotes! %d", len(p.acceptVotes)) if p.cfg.Manager.GetArbitrators().HasArbitersMajorityCount(len(p.acceptVotes)) { log.Info("Collect majority signs, finish proposal.") @@ -1056,6 +1058,7 @@ func NewDispatcherAndIllegalMonitor(cfg ProposalDispatcherConfig) ( *ProposalDispatcher, *IllegalBehaviorMonitor) { p := &ProposalDispatcher{ cfg: cfg, + finishedHeight: cfg.BestHeight, processingBlock: nil, processingProposal: nil, acceptVotes: make(map[common.Uint256]*payload.DPOSProposalVote), diff --git a/dpos/manager/view.go b/dpos/manager/view.go index cfeb15bf8..dc4c84779 100644 --- a/dpos/manager/view.go +++ b/dpos/manager/view.go @@ -61,6 +61,8 @@ func (v *view) ChangeView(viewOffset *uint32, now time.Time) { currentArbiter := v.arbitrators.GetNextOnDutyArbitrator(*viewOffset) v.isDposOnDuty = bytes.Equal(currentArbiter, v.publicKey) + log.Info("v0 viewOffset:", *viewOffset) + log.Info("current onduty arbiter:", common.BytesToHexString(currentArbiter)) @@ -70,8 +72,11 @@ func (v *view) ChangeView(viewOffset *uint32, now time.Time) { func (v *view) ChangeViewV1(viewOffset *uint32, now time.Time) { arbitersCount := v.arbitrators.GetArbitersCount() - + log.Info("ChangeViewV1 viewOffset:", *viewOffset) offset, offsetTime := v.calculateOffsetTimeV1(*viewOffset, v.viewStartTime, now, uint32(arbitersCount)) + if *viewOffset == offset { + return + } *viewOffset = offset v.viewStartTime = now.Add(-offsetTime) @@ -80,6 +85,7 @@ func (v *view) ChangeViewV1(viewOffset *uint32, now time.Time) { currentArbiter := v.arbitrators.GetNextOnDutyArbitrator(*viewOffset) v.isDposOnDuty = bytes.Equal(currentArbiter, v.publicKey) + log.Info("ChangeViewV1 viewOffset:", *viewOffset) log.Info("current onduty arbiter:", common.BytesToHexString(currentArbiter)) @@ -140,7 +146,7 @@ func (v *view) calculateOffsetTimeV2(currentViewOffset uint32, startTime time.Ti func (v *view) TryChangeView(viewOffset *uint32, now time.Time) bool { if now.After(v.viewStartTime.Add(v.signTolerance)) { - log.Info("[TryChangeView] succeed") + log.Info("[TryChangeView] succeed 1") v.ChangeView(viewOffset, now) return true } @@ -149,7 +155,7 @@ func (v *view) TryChangeView(viewOffset *uint32, now time.Time) bool { func (v *view) TryChangeViewV1(viewOffset *uint32, now time.Time) bool { if now.After(v.viewStartTime.Add(v.signTolerance)) { - log.Info("[TryChangeView] succeed") + log.Info("[TryChangeView] succeed 2") v.ChangeViewV1(viewOffset, now) return true } diff --git a/dpos/state/arbitrators.go b/dpos/state/arbitrators.go index 3a69ca0f0..168572c65 100644 --- a/dpos/state/arbitrators.go +++ b/dpos/state/arbitrators.go @@ -127,7 +127,8 @@ func GetOwnerKeyStandardProgramHash(ownerKey []byte) (ownKeyProgramHash *common. if len(ownerKey) == crypto.NegativeBigLength { ownKeyProgramHash, err = contract.PublicKeyToStandardProgramHash(ownerKey) } else { - ownKeyProgramHash = common.ToProgramHash(byte(contract.PrefixStandard), ownerKey) + //PrefixMultiSig + ownKeyProgramHash = common.ToProgramHash(byte(contract.PrefixMultiSig), ownerKey) } return ownKeyProgramHash, err } @@ -181,6 +182,7 @@ func (a *Arbiters) recoverFromCheckPoints(point *CheckPoint) { // reset history a.History = utils.NewHistory(maxHistoryCapacity) a.State.History = utils.NewHistory(maxHistoryCapacity) + a.State.InactiveHistory = utils.NewHistory(maxHistoryCapacity) a.DutyIndex = point.DutyIndex a.CurrentArbitrators = point.CurrentArbitrators @@ -279,7 +281,6 @@ func (a *Arbiters) CheckNextTurnDPOSInfoTx(block *types.Block) error { if needNextTurnDposInfo { needNextTurnDPOSInfoCount = 1 } - if nextTurnDPOSInfoTxCount != needNextTurnDPOSInfoCount { return fmt.Errorf("current block height %d, NextTurnDPOSInfo "+ "transaction count should be %d, current block contains %d", @@ -782,7 +783,6 @@ func (a *Arbiters) getDPoSV2RewardsV2(dposReward common.Fixed64, sponsor []byte, rewards[ownerAddr] += dposNodeReward log.Debugf("getDPoSV2Rewards totalUsedVotesReward %s dposNodeReward %s, \n", totalUsedVotesReward, dposNodeReward) } - return rewards } @@ -2506,12 +2506,12 @@ func (a *Arbiters) getCRCArbitersV2(height uint32) (map[common.Uint168]ArbiterMe } else { pk = cr.DPOSPublicKey } - crPublicKey := cr.Info.Code[1 : len(cr.Info.Code)-1] + ownerKey := common.GetOwnerKey(cr.Info.Code) isNormal := true if height >= claimHeight && cr.MemberState != state.MemberElected { isNormal = false } - ar, err := NewCRCArbiter(pk, crPublicKey, cr, isNormal) + ar, err := NewCRCArbiter(pk, ownerKey, cr, isNormal) if err != nil { return nil, 0, err } @@ -2563,12 +2563,12 @@ func (a *Arbiters) getCRCArbitersV1(height uint32) (map[common.Uint168]ArbiterMe } else { pk = cr.DPOSPublicKey } - crPublicKey := cr.Info.Code[1 : len(cr.Info.Code)-1] + ownerKey := common.GetOwnerKey(cr.Info.Code) isNormal := true if height >= claimHeight && cr.MemberState != state.MemberElected { isNormal = false } - ar, err := NewCRCArbiter(pk, crPublicKey, cr, isNormal) + ar, err := NewCRCArbiter(pk, ownerKey, cr, isNormal) if err != nil { return nil, err } diff --git a/dpos/state/checkpoint.go b/dpos/state/checkpoint.go index 04a4b6133..8ccf91382 100644 --- a/dpos/state/checkpoint.go +++ b/dpos/state/checkpoint.go @@ -81,6 +81,20 @@ func (c *CheckPoint) OnRollbackSeekTo(height uint32) { c.arbitrators.RollbackSeekTo(height) } +func (c *CheckPoint) OnReset() error { + log.Info("dpos state OnReset") + ar := &Arbiters{} + ar.State = &State{ + StateKeyFrame: NewStateKeyFrame(), + } + if err := ar.initArbitrators(c.arbitrators.ChainParams); err != nil { + return err + } + c.initFromArbitrators(ar) + c.arbitrators.RecoverFromCheckPoints(c) + return nil +} + func (c *CheckPoint) OnRollbackTo(height uint32) error { if height < c.StartHeight() { ar := &Arbiters{} diff --git a/dpos/state/crcarbiter.go b/dpos/state/crcarbiter.go index 0c0c62e8e..2a012711a 100644 --- a/dpos/state/crcarbiter.go +++ b/dpos/state/crcarbiter.go @@ -58,6 +58,8 @@ func (c *crcArbiter) GetType() ArbiterType { return CRC } +// GetOwnerKey standard is publickey , multisign is code +// GetOwnerKey func (c *crcArbiter) GetOwnerPublicKey() []byte { return c.getPublicKey() } @@ -83,9 +85,9 @@ func (c *crcArbiter) Clone() ArbiterMember { return result } +// get owner key func (c *crcArbiter) getPublicKey() []byte { - // todo support for multi public key later - return c.crMember.Info.Code[1 : len(c.crMember.Info.Code)-1] + return common.GetOwnerKey(c.crMember.Info.Code) } func NewCRCArbiter(nodePK []byte, ownerPK []byte, cr *state.CRMember, diff --git a/dpos/state/state.go b/dpos/state/state.go index fbfc93834..1b8d2661c 100644 --- a/dpos/state/state.go +++ b/dpos/state/state.go @@ -594,6 +594,8 @@ type State struct { ChainParams *config.Configuration mtx sync.RWMutex History *utils.History + //for countArbitratorsInactivity* use + InactiveHistory *utils.History getHeight func() uint32 isCurrent func() bool @@ -1289,6 +1291,8 @@ func (s *State) ProcessBlock(block *types.Block, confirm *payload.Confirm, dutyI s.recordLastBlockTime(block) s.tryRevertToPOWByStateOfCRMember(block.Height) s.tryUpdateLastIrreversibleHeight(block.Height) + // Commit changes here if no errors found. + s.History.Commit(block.Height) if confirm != nil { if block.Height > s.DPoSV2ActiveHeight { @@ -1301,14 +1305,12 @@ func (s *State) ProcessBlock(block *types.Block, confirm *payload.Confirm, dutyI s.countArbitratorsInactivityV0(block.Height, confirm) } } - // todo remove me if block.Height > s.ChainParams.DPoSV2StartHeight { msg2.SetPayloadVersion(msg2.DPoSV2Version) } - // Commit changes here if no errors found. - s.History.Commit(block.Height) + s.InactiveHistory.Commit(block.Height) if block.Height >= s.ChainParams.DPoSV2StartHeight && len(s.WithdrawableTxInfo) != 0 { @@ -1554,28 +1556,41 @@ func (s *State) processTransactions(txs []interfaces.Transaction, height uint32) // Check if any pending producers has got 6 confirms, set them to activate. activateProducerFromPending := func(key string, producer *Producer) { + oriState := producer.state s.History.Append(height, func() { - producer.state = Active - s.ActivityProducers[key] = producer - delete(s.PendingProducers, key) + if canChangeProducerState(producer.state, Active) { + producer.state = Active + s.ActivityProducers[key] = producer + delete(s.PendingProducers, key) + } }, func() { - producer.state = Pending - s.PendingProducers[key] = producer - delete(s.ActivityProducers, key) + if canChangeProducerState(oriState, Active) { + producer.state = oriState + //is not correct + s.PendingProducers[key] = producer + delete(s.ActivityProducers, key) + } }) } // Check if any pending inactive producers has got 6 confirms, // then set them to activate. activateProducerFromInactive := func(key string, producer *Producer) { + //producer.state may be illegaled by tx but not commit by history + oriState := producer.state s.History.Append(height, func() { - producer.state = Active - s.ActivityProducers[key] = producer - delete(s.InactiveProducers, key) + if canChangeProducerState(producer.state, Active) { + producer.state = Active + s.ActivityProducers[key] = producer + delete(s.InactiveProducers, key) + } }, func() { - producer.state = Inactive - s.InactiveProducers[key] = producer - delete(s.ActivityProducers, key) + if canChangeProducerState(oriState, Active) { + producer.state = oriState + // is not correct + s.InactiveProducers[key] = producer + delete(s.ActivityProducers, key) + } }) } @@ -1583,31 +1598,35 @@ func (s *State) processTransactions(txs []interfaces.Transaction, height uint32) oriState := producer.state oriDepositAmount := producer.depositAmount s.History.Append(height, func() { - producer.state = Canceled - producer.depositAmount -= state.MinDPoSV2DepositAmount - s.CanceledProducers[key] = producer - switch oriState { - case Active: - delete(s.ActivityProducers, key) - case Inactive: - delete(s.InactiveProducers, key) - case Illegal: - delete(s.IllegalProducers, key) + if canChangeProducerState(producer.state, Canceled) { + producer.state = Canceled + producer.depositAmount -= state.MinDPoSV2DepositAmount + s.CanceledProducers[key] = producer + switch oriState { + case Active: + delete(s.ActivityProducers, key) + case Inactive: + delete(s.InactiveProducers, key) + case Illegal: + delete(s.IllegalProducers, key) + } + delete(s.Nicknames, producer.info.NickName) } - delete(s.Nicknames, producer.info.NickName) }, func() { - producer.state = oriState - producer.depositAmount = oriDepositAmount - switch oriState { - case Active: - s.ActivityProducers[key] = producer - case Inactive: - s.InactiveProducers[key] = producer - case Illegal: - s.IllegalProducers[key] = producer + if canChangeProducerState(oriState, Canceled) { + producer.state = oriState + producer.depositAmount = oriDepositAmount + switch oriState { + case Active: + s.ActivityProducers[key] = producer + case Inactive: + s.InactiveProducers[key] = producer + case Illegal: + s.IllegalProducers[key] = producer + } + delete(s.CanceledProducers, key) + s.Nicknames[producer.info.NickName] = struct{}{} } - delete(s.CanceledProducers, key) - s.Nicknames[producer.info.NickName] = struct{}{} }) } //key is referkey stake address @@ -1667,18 +1686,25 @@ func (s *State) processTransactions(txs []interfaces.Transaction, height uint32) // Check if any pending illegal producers has got 6 confirms, // then set them to activate. activateProducerFromIllegal := func(key string, producer *Producer) { + oriState := producer.state s.History.Append(height, func() { - producer.state = Active - s.ActivityProducers[key] = producer - delete(s.IllegalProducers, key) + if canChangeProducerState(producer.state, Active) { + producer.state = Active + s.ActivityProducers[key] = producer + delete(s.IllegalProducers, key) + } }, func() { - producer.state = Illegal - s.IllegalProducers[key] = producer - delete(s.ActivityProducers, key) + if canChangeProducerState(oriState, Active) { + producer.state = oriState + s.IllegalProducers[key] = producer + delete(s.ActivityProducers, key) + } + }) } if len(s.PendingProducers) > 0 { + //may be canceld by CancelProducer tx but not commit so we can not change for key, producer := range s.PendingProducers { if height-producer.registerHeight+1 >= ActivateDuration { activateProducerFromPending(key, producer) @@ -2414,6 +2440,44 @@ func (s *State) ReturnDeposit(tx interfaces.Transaction, height uint32) { s.returnDeposit(tx, height) } +func canChangeProducerState(nowState, targetState ProducerState) bool { + switch targetState { + case Active: //nowState first is(Pending,Inactive,Illegal) maybe canceled by CancelProducer tx before history commit here + if nowState != Pending && nowState != Inactive && nowState != Illegal { + return false + } else { + return true + } + case Inactive: //nowState first is(Active) then maybe canceled or illegaled before history commit here + if nowState != Active { + return false + } else { + return true + } + case Canceled: //done + //during cancelDposV2AndDposV1V2Producer function . if one producer stakeuntil expired and sametime with CancelProducer + //first is(Pending,Inactive),then become canceled by CancelProducer before history commit here + if nowState != Pending && nowState != Inactive { //&& nowState != Illegal + return false + } else { + return true + } + case Illegal: // only by illegal tx no conflict + if nowState != Active && nowState != Inactive && nowState != Illegal && nowState != Canceled { + return false + } else { + return true + } + case Returned: //only by return deposite tx no conflict + if nowState != Canceled { + return false + } else { + return true + } + } + return false +} + // returnDeposit change producer state to ReturnedDeposit func (s *State) returnDeposit(tx interfaces.Transaction, height uint32) { var inputValue common.Fixed64 @@ -2479,16 +2543,24 @@ func (s *State) processNextTurnDPOSInfo(tx interfaces.Transaction, height uint32 }) } -func (s *State) getCRMembersOwnerPublicKey(CRCommitteeDID common.Uint168) []byte { +func (s *State) getCRMembersOwnerKey(CRCommitteeDID common.Uint168) []byte { if s.getCurrentCRMembers != nil && s.getNextCRMembers != nil { for _, cr := range s.getCurrentCRMembers() { if cr.Info.DID.IsEqual(CRCommitteeDID) { - return cr.Info.Code[1 : len(cr.Info.Code)-1] + if len(cr.Info.Code) == 35 { + return cr.Info.Code[1 : len(cr.Info.Code)-1] + } else { + return cr.Info.Code + } } } for _, cr := range s.getNextCRMembers() { if cr.Info.DID.IsEqual(CRCommitteeDID) { - return cr.Info.Code[1 : len(cr.Info.Code)-1] + if len(cr.Info.Code) == 35 { + return cr.Info.Code[1 : len(cr.Info.Code)-1] + } else { + return cr.Info.Code + } } } } @@ -2517,38 +2589,38 @@ func (s *State) processCRCouncilMemberClaimNode(tx interfaces.Transaction, heigh claimNodePayload := tx.Payload().(*payload.CRCouncilMemberClaimNode) strNewNodePublicKey := common.BytesToHexString(claimNodePayload.NodePublicKey) - ownerPublicKey := s.getCRMembersOwnerPublicKey(claimNodePayload.CRCouncilCommitteeDID) - if ownerPublicKey == nil { + ownerKey := s.getCRMembersOwnerKey(claimNodePayload.CRCouncilCommitteeDID) + if ownerKey == nil { log.Error("processCRCouncilMemberClaimNode cr member is not exist") return } - strOwnerPubkey := common.BytesToHexString(ownerPublicKey) + strOwnerkey := common.BytesToHexString(ownerKey) switch tx.PayloadVersion() { - case payload.CurrentCRClaimDPoSNodeVersion: - strOldNodePublicKey := s.getCurrentCRNodePublicKeyStr(strOwnerPubkey) + case payload.CurrentCRClaimDPoSNodeVersion, payload.CurrentCRClaimDPoSNodeMultiSignVersion: + strOldNodePublicKey := s.getCurrentCRNodePublicKeyStr(strOwnerkey) s.History.Append(height, func() { - s.CurrentCRNodeOwnerKeys[strNewNodePublicKey] = strOwnerPubkey + s.CurrentCRNodeOwnerKeys[strNewNodePublicKey] = strOwnerkey if strOldNodePublicKey != "" { delete(s.CurrentCRNodeOwnerKeys, strOldNodePublicKey) } }, func() { delete(s.CurrentCRNodeOwnerKeys, strNewNodePublicKey) if strOldNodePublicKey != "" { - s.CurrentCRNodeOwnerKeys[strOldNodePublicKey] = strOwnerPubkey + s.CurrentCRNodeOwnerKeys[strOldNodePublicKey] = strOwnerkey } }) - case payload.NextCRClaimDPoSNodeVersion: - strOldNodePublicKey := s.getNextCRNodePublicKeyStr(strOwnerPubkey) + case payload.NextCRClaimDPoSNodeVersion, payload.NextCRClaimDPoSNodeMultiSignVersion: + strOldNodePublicKey := s.getNextCRNodePublicKeyStr(strOwnerkey) s.History.Append(height, func() { - s.NextCRNodeOwnerKeys[strNewNodePublicKey] = strOwnerPubkey + s.NextCRNodeOwnerKeys[strNewNodePublicKey] = strOwnerkey if strOldNodePublicKey != "" { delete(s.NextCRNodeOwnerKeys, strOldNodePublicKey) } }, func() { delete(s.NextCRNodeOwnerKeys, strNewNodePublicKey) if strOldNodePublicKey != "" { - s.NextCRNodeOwnerKeys[strOldNodePublicKey] = strOwnerPubkey + s.NextCRNodeOwnerKeys[strOldNodePublicKey] = strOwnerkey } }) } @@ -3324,7 +3396,7 @@ func (s *State) countArbitratorsInactivityV3(height uint32, workedInRound := mem.WorkedInRound s.updateCRMemberInactiveCountV2(lastPosition, needReset, workedInRound, mem, height, key) if needReset && workedInRound != true { - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { mem.WorkedInRound = true }, func() { mem.WorkedInRound = false @@ -3344,7 +3416,7 @@ func (s *State) countArbitratorsInactivityV3(height uint32, s.updateInactiveCountV2(lastPosition, needReset, workedInRound, producer, height, key) if needReset && producer.workedInRound != true { - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { producer.workedInRound = true }, func() { producer.workedInRound = false @@ -3357,7 +3429,7 @@ func (s *State) countArbitratorsInactivityV3(height uint32, for _, p := range ps { cp := p // reset workedInRound value - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { cp.workedInRound = false }, func() { cp.workedInRound = true @@ -3368,7 +3440,7 @@ func (s *State) countArbitratorsInactivityV3(height uint32, for _, m := range ms { cm := m // reset workedInRound value - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { cm.WorkedInRound = false }, func() { cm.WorkedInRound = true @@ -3381,7 +3453,7 @@ func (s *State) updateCRMemberInactiveCountV2(lastPosition, needReset, workedInR // if it's the last position and not working in Round then we should add inactiveCountV2++ if lastPosition && !needReset && !workedInRound { originInactiveCountV2 := member.InactiveCountV2 - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { member.InactiveCountV2 += 1 if member.InactiveCountV2 >= 3 { member.MemberState = state.MemberInactive @@ -3401,7 +3473,7 @@ func (s *State) updateCRMemberInactiveCountV2(lastPosition, needReset, workedInR }) } else if lastPosition && (needReset == true || workedInRound) { originInactiveCountV2 := member.InactiveCountV2 - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { member.InactiveCountV2 = 0 }, func() { member.InactiveCountV2 = originInactiveCountV2 @@ -3413,7 +3485,7 @@ func (s *State) updateInactiveCountV2(lastPosition, needReset, workedInRound boo // if it's the last position and not working in Round then we should add inactiveCountV2++ if lastPosition && !needReset && !workedInRound { originInactiveCountV2 := producer.inactiveCountV2 - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { producer.inactiveCountV2 += 1 if producer.inactiveCountV2 >= 3 { s.setInactiveProducer(producer, key, height, false) @@ -3427,7 +3499,7 @@ func (s *State) updateInactiveCountV2(lastPosition, needReset, workedInRound boo }) } else if lastPosition && (needReset == true || workedInRound) { originInactiveCountV2 := producer.inactiveCountV2 - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { producer.inactiveCountV2 = 0 }, func() { producer.inactiveCountV2 = originInactiveCountV2 @@ -3493,7 +3565,7 @@ func (s *State) countArbitratorsInactivityV2(height uint32, } oriLastUpdateInactiveHeight := producer.lastUpdateInactiveHeight oriSelected := producer.selected - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { s.tryUpdateInactivityV2(key, producer, needReset, height) }, func() { s.tryRevertInactivity(key, producer, needReset, height, @@ -3502,7 +3574,7 @@ func (s *State) countArbitratorsInactivityV2(height uint32, } else { oriState := cr.MemberState oriInactiveCount := cr.InactiveCount - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { s.tryUpdateCRMemberInactivity(cr.Info.DID, needReset, height) }, func() { s.tryRevertCRMemberInactivity(cr.Info.DID, oriState, oriInactiveCount, height) @@ -3525,7 +3597,7 @@ func (s *State) countArbitratorsInactivityV2(height uint32, } oriLastUpdateInactiveHeight := producer.lastUpdateInactiveHeight oriSelected := producer.selected - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { s.tryUpdateInactivityV2(key, producer, needReset, height) }, func() { s.tryRevertInactivity(key, producer, needReset, height, @@ -3578,7 +3650,7 @@ func (s *State) countArbitratorsInactivityV1(height uint32, } oriState := cr.MemberState oriInactiveCount := cr.InactiveCountingHeight - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { s.tryUpdateCRMemberInactivity(cr.Info.DID, needReset, height) }, func() { s.tryRevertCRMemberInactivity(cr.Info.DID, oriState, oriInactiveCount, height) @@ -3596,7 +3668,7 @@ func (s *State) countArbitratorsInactivityV1(height uint32, oriInactiveCount := producer.inactiveCount oriLastUpdateInactiveHeight := producer.lastUpdateInactiveHeight oriSelected := producer.selected - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { s.tryUpdateInactivity(key, producer, needReset, height) }, func() { s.tryRevertInactivity(key, producer, needReset, height, @@ -3651,7 +3723,7 @@ func (s *State) countArbitratorsInactivityV0(height uint32, } oriLastUpdateInactiveHeight := producer.lastUpdateInactiveHeight oriSelected := producer.selected - s.History.Append(height, func() { + s.InactiveHistory.Append(height, func() { s.tryUpdateInactivity(key, producer, needReset, height) }, func() { s.tryRevertInactivity(key, producer, needReset, height, @@ -3735,6 +3807,7 @@ func (s *State) RollbackSeekTo(height uint32) { s.mtx.Lock() defer s.mtx.Unlock() s.History.RollbackSeekTo(height) + s.InactiveHistory.RollbackSeekTo(height) } // RollbackTo restores the database state to the given height, if no enough @@ -3742,7 +3815,9 @@ func (s *State) RollbackSeekTo(height uint32) { func (s *State) RollbackTo(height uint32) error { s.mtx.Lock() defer s.mtx.Unlock() - return s.History.RollbackTo(height) + s.History.RollbackTo(height) + //todo + return s.InactiveHistory.RollbackTo(height) } // GetHistory returns a History state instance storing the producers and votes @@ -3885,6 +3960,7 @@ func NewState(chainParams *config.Configuration, getArbiters func() []*ArbiterIn isInElectionPeriod: isInElectionPeriod, GetProducerDepositAmount: getProducerDepositAmount, History: utils.NewHistory(maxHistoryCapacity), + InactiveHistory: utils.NewHistory(maxHistoryCapacity), StateKeyFrame: NewStateKeyFrame(), tryUpdateCRMemberInactivity: tryUpdateCRMemberInactivity, tryRevertCRMemberInactivity: tryRevertCRMemberInactivityfunc, diff --git a/elanet/netsync/manager.go b/elanet/netsync/manager.go index bae07a6b1..82f8583b4 100644 --- a/elanet/netsync/manager.go +++ b/elanet/netsync/manager.go @@ -437,6 +437,7 @@ func (sm *SyncManager) handleBlockMsg(bmsg *blockMsg) { log.Debug("sm.chain.BestChain.Height:", sm.chain.BestChain.Height, "sm.syncHeight:", sm.syncHeight, "isOrphan:", isOrphan) + // Request the parents for the orphan block from the peer that sent it. if isOrphan { orphanRoot := sm.chain.GetOrphanRoot(&blockHash) @@ -568,7 +569,6 @@ func (sm *SyncManager) handleInvMsg(imsg *invMsg) { state.requestQueue = append(state.requestQueue, iv) continue } - if iv.Type == msg.InvTypeConfirmedBlock { // The block is an orphan block that we already have. // When the existing orphan was processed, it requested @@ -659,7 +659,7 @@ func (sm *SyncManager) handleInvMsg(imsg *invMsg) { } // maxBlockLocators = 500 - if len(gdmsg.InvList) == 500 { + if len(invVects) == 500 { locator := sm.chain.GetOrphanBlockLocator(invVects) log.Info("PushGetBlocksMsg 2:", locator, "count:", len(gdmsg.InvList)) if err := peer.PushGetBlocksMsg(locator, &zeroHash); err != nil { diff --git a/mempool/conflictfunc.go b/mempool/conflictfunc.go index 5fccefbf2..fd6816a1c 100644 --- a/mempool/conflictfunc.go +++ b/mempool/conflictfunc.go @@ -421,9 +421,9 @@ func strRegisterCRPublicKey(tx interfaces.Transaction) (interface{}, error) { } if signType == vm.CHECKMULTISIG { - return hex.EncodeToString(p.Code), nil + return hex.EncodeToString(code), nil } else if signType == vm.CHECKSIG { - return hex.EncodeToString(p.Code[1 : len(p.Code)-1]), nil + return hex.EncodeToString(code[1 : len(code)-1]), nil } else if bytes.Equal(p.Code, []byte{}) && contract.IsSchnorr(code) { return hex.EncodeToString(code[2:]), nil } else { diff --git a/mempool/txpoolcheckpoint.go b/mempool/txpoolcheckpoint.go index d8e4a422c..0f2204998 100644 --- a/mempool/txpoolcheckpoint.go +++ b/mempool/txpoolcheckpoint.go @@ -76,6 +76,10 @@ func (c *txPoolCheckpoint) GetHeight() uint32 { return c.height } +func (c *txPoolCheckpoint) OnReset() error { + return nil +} + func (c *txPoolCheckpoint) SetHeight(height uint32) { c.height = height } diff --git a/pow/service.go b/pow/service.go index 3810b2ca6..d31f62820 100644 --- a/pow/service.go +++ b/pow/service.go @@ -307,11 +307,6 @@ func (pow *Service) GenerateBlock(minerAddr string, var proposalsUsedAmount common.Fixed64 for _, tx := range txs { - - if tx.IsIllegalProposalTx() || tx.IsIllegalVoteTx() { - continue - } - size := totalTxsSize + tx.GetSize() if size > int(pact.MaxBlockContextSize) { continue @@ -440,6 +435,10 @@ func (pow *Service) DiscreteMining(n uint32) ([]*common.Uint256, error) { Block: msgBlock, }) if err != nil { + pow.mutex.Lock() + pow.started = false + pow.discreteMining = false + pow.mutex.Unlock() return blockHashes, nil } @@ -455,6 +454,11 @@ func (pow *Service) DiscreteMining(n uint32) ([]*common.Uint256, error) { } } } + + pow.mutex.Lock() + pow.started = false + pow.discreteMining = false + pow.mutex.Unlock() return blockHashes, nil } } diff --git a/test/unit/dposstate_test.go b/test/unit/dposstate_test.go index 648fb6cc7..efb300978 100644 --- a/test/unit/dposstate_test.go +++ b/test/unit/dposstate_test.go @@ -1697,6 +1697,7 @@ func TestState_CountArbitratorsInactivityV1(t *testing.T) { }, }) state.History.Commit(height) + state.InactiveHistory.Commit(height) } // check the status of random DPOS node. diff --git a/test/unit/txvalidator_test.go b/test/unit/txvalidator_test.go index c54cca6ca..0fa2542e5 100644 --- a/test/unit/txvalidator_test.go +++ b/test/unit/txvalidator_test.go @@ -3254,7 +3254,8 @@ func (s *txValidatorTestSuite) TestCheckRegisterCRTransaction() { s.Chain.GetCRCommittee().GetState().CodeCIDMap[codeStr1] = *cid1 s.Chain.GetCRCommittee().GetState().Candidates[*cid1] = &crstate.Candidate{} err, _ = txn.SpecialContextCheck() - s.EqualError(err, "transaction validate error: payload content invalid:cid "+cid1.String()+" already exist") + cid1Addr, _ := cid1.ToAddress() + s.EqualError(err, "transaction validate error: payload content invalid:cid "+cid1Addr+" already exist") delete(s.Chain.GetCRCommittee().GetState().Candidates, *cid1) // Give an invalid code in payload @@ -3339,35 +3340,35 @@ func (s *txValidatorTestSuite) TestCheckRegisterCRTransaction() { BlockChain: s.Chain, }) err, _ = txn.SpecialContextCheck() - s.EqualError(err, "transaction validate error: payload content invalid:CR not support multi sign code") - - txn = s.getMultiSigRegisterCRTx( - []string{publicKeyStr1, publicKeyStr2, publicKeyStr3}, - []string{privateKeyStr1, privateKeyStr2}, nickName1) - txn = CreateTransactionByType(txn, s.Chain) - txn.SetParameters(&transaction.TransactionParameters{ - Transaction: txn, - BlockHeight: votingHeight, - TimeStamp: s.Chain.BestChain.Timestamp, - Config: s.Chain.GetParams(), - BlockChain: s.Chain, - }) - err, _ = txn.SpecialContextCheck() - s.EqualError(err, "transaction validate error: payload content invalid:CR not support multi sign code") - - txn = s.getMultiSigRegisterCRTx( - []string{publicKeyStr1, publicKeyStr2, publicKeyStr3}, - []string{privateKeyStr1}, nickName1) - txn = CreateTransactionByType(txn, s.Chain) - txn.SetParameters(&transaction.TransactionParameters{ - Transaction: txn, - BlockHeight: votingHeight, - TimeStamp: s.Chain.BestChain.Timestamp, - Config: s.Chain.GetParams(), - BlockChain: s.Chain, - }) - err, _ = txn.SpecialContextCheck() - s.EqualError(err, "transaction validate error: payload content invalid:CR not support multi sign code") + s.EqualError(err, "transaction validate error: payload content invalid:CRInfoVersion or CRInfoDIDVersion match standard code") + + //txn = s.getMultiSigRegisterCRTx( + // []string{publicKeyStr1, publicKeyStr2, publicKeyStr3}, + // []string{privateKeyStr1, privateKeyStr2}, nickName1) + //txn = CreateTransactionByType(txn, s.Chain) + //txn.SetParameters(&transaction.TransactionParameters{ + // Transaction: txn, + // BlockHeight: votingHeight, + // TimeStamp: s.Chain.BestChain.Timestamp, + // Config: s.Chain.GetParams(), + // BlockChain: s.Chain, + //}) + //err, _ = txn.SpecialContextCheck() + //s.EqualError(err, "transaction validate error: payload content invalid:CR not support multi sign code") + // + //txn = s.getMultiSigRegisterCRTx( + // []string{publicKeyStr1, publicKeyStr2, publicKeyStr3}, + // []string{privateKeyStr1}, nickName1) + //txn = CreateTransactionByType(txn, s.Chain) + //txn.SetParameters(&transaction.TransactionParameters{ + // Transaction: txn, + // BlockHeight: votingHeight, + // TimeStamp: s.Chain.BestChain.Timestamp, + // Config: s.Chain.GetParams(), + // BlockChain: s.Chain, + //}) + //err, _ = txn.SpecialContextCheck() + //s.EqualError(err, "transaction validate error: payload content invalid:CR not support multi sign code") //check register cr with CRInfoDIDVersion txn2 := s.getRegisterCRTx(publicKeyStr1, privateKeyStr1, nickName1, diff --git a/wallet/coincheckpoint.go b/wallet/coincheckpoint.go index 745039a3f..e3a5bd30e 100644 --- a/wallet/coincheckpoint.go +++ b/wallet/coincheckpoint.go @@ -131,6 +131,10 @@ func (ccp *CoinsCheckPoint) Generator() func(buf []byte) checkpoint.ICheckPoint } } +func (ccp *CoinsCheckPoint) OnReset() error { + return nil +} + func (ccp *CoinsCheckPoint) LogError(err error) { log.Warn(err.Error()) }