github.com/nnlgsakib/mind-dpos@v0.0.0-20230606105614-f3c8ca06f808/consensus/alien/api.go (about) 1 // Copyright 2018 The gttc Authors 2 // This file is part of the gttc library. 3 // 4 // The gttc library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The gttc library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the gttc library. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package alien implements the delegated-proof-of-stake consensus engine. 18 19 package alien 20 21 import ( 22 "github.com/TTCECO/gttc/common" 23 "github.com/TTCECO/gttc/consensus" 24 "github.com/TTCECO/gttc/core/types" 25 "github.com/TTCECO/gttc/rpc" 26 "math/big" 27 ) 28 29 // API is a user facing RPC API to allow controlling the signer and voting 30 // mechanisms of the delegated-proof-of-stake scheme. 31 type API struct { 32 chain consensus.ChainReader 33 alien *Alien 34 } 35 36 // GetSnapshot retrieves the state snapshot at a given block. 37 func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) { 38 // Retrieve the requested block number (or current if none requested) 39 var header *types.Header 40 if number == nil || *number == rpc.LatestBlockNumber { 41 header = api.chain.CurrentHeader() 42 } else { 43 header = api.chain.GetHeaderByNumber(uint64(number.Int64())) 44 } 45 // Ensure we have an actually valid block and return its snapshot 46 if header == nil { 47 return nil, errUnknownBlock 48 } 49 return api.alien.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, nil, defaultLoopCntRecalculateSigners) 50 51 } 52 53 // GetSnapshotAtHash retrieves the state snapshot at a given block. 54 func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) { 55 header := api.chain.GetHeaderByHash(hash) 56 if header == nil { 57 return nil, errUnknownBlock 58 } 59 return api.alien.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, nil, defaultLoopCntRecalculateSigners) 60 } 61 62 // GetSnapshotAtNumber retrieves the state snapshot at a given block. 63 func (api *API) GetSnapshotAtNumber(number uint64) (*Snapshot, error) { 64 header := api.chain.GetHeaderByNumber(number) 65 if header == nil { 66 return nil, errUnknownBlock 67 } 68 return api.alien.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, nil, defaultLoopCntRecalculateSigners) 69 } 70 71 // GetSnapshotByHeaderTime retrieves the state snapshot by timestamp of header. 72 // snapshot.header.time <= targetTime < snapshot.header.time + period 73 // todo: add confirm headertime in return snapshot, to minimize the request from side chain 74 func (api *API) GetSnapshotByHeaderTime(targetTime uint64, scHash common.Hash) (*Snapshot, error) { 75 header := api.chain.CurrentHeader() 76 period := new(big.Int).SetUint64(api.chain.Config().Alien.Period) 77 target := new(big.Int).SetUint64(targetTime) 78 if ceil := new(big.Int).Add(header.Time, period); header == nil || target.Cmp(ceil) > 0 { 79 return nil, errUnknownBlock 80 } 81 82 minN := new(big.Int).SetUint64(api.chain.Config().Alien.MaxSignerCount) 83 maxN := new(big.Int).Set(header.Number) 84 nextN := new(big.Int).SetInt64(0) 85 isNext := false 86 for { 87 if ceil := new(big.Int).Add(header.Time, period); target.Cmp(header.Time) >= 0 && target.Cmp(ceil) < 0 { 88 snap, err := api.alien.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil, nil, defaultLoopCntRecalculateSigners) 89 90 // replace coinbase by signer settings 91 var scSigners []*common.Address 92 for _, signer := range snap.Signers { 93 replaced := false 94 if _, ok := snap.SCCoinbase[*signer]; ok { 95 if addr, ok := snap.SCCoinbase[*signer][scHash]; ok { 96 replaced = true 97 scSigners = append(scSigners, &addr) 98 } 99 } 100 if !replaced { 101 scSigners = append(scSigners, signer) 102 } 103 } 104 mcs := Snapshot{LoopStartTime: snap.LoopStartTime, Period: snap.Period, Signers: scSigners, Number: snap.Number} 105 if _, ok := snap.SCNoticeMap[scHash]; ok { 106 mcs.SCNoticeMap = make(map[common.Hash]*CCNotice) 107 mcs.SCNoticeMap[scHash] = snap.SCNoticeMap[scHash] 108 } 109 return &mcs, err 110 } else { 111 if minNext := new(big.Int).Add(minN, big.NewInt(1)); maxN.Cmp(minN) == 0 || maxN.Cmp(minNext) == 0 { 112 if !isNext && maxN.Cmp(minNext) == 0 { 113 var maxHeaderTime, minHeaderTime *big.Int 114 maxH := api.chain.GetHeaderByNumber(maxN.Uint64()) 115 if maxH != nil { 116 maxHeaderTime = new(big.Int).Set(maxH.Time) 117 } else { 118 break 119 } 120 minH := api.chain.GetHeaderByNumber(minN.Uint64()) 121 if minH != nil { 122 minHeaderTime = new(big.Int).Set(minH.Time) 123 } else { 124 break 125 } 126 period = period.Sub(maxHeaderTime, minHeaderTime) 127 isNext = true 128 } else { 129 break 130 } 131 } 132 // calculate next number 133 nextN.Sub(target, header.Time) 134 nextN.Div(nextN, period) 135 nextN.Add(nextN, header.Number) 136 137 // if nextN beyond the [minN,maxN] then set nextN = (min+max)/2 138 if nextN.Cmp(maxN) >= 0 || nextN.Cmp(minN) <= 0 { 139 nextN.Add(maxN, minN) 140 nextN.Div(nextN, big.NewInt(2)) 141 } 142 // get new header 143 header = api.chain.GetHeaderByNumber(nextN.Uint64()) 144 if header == nil { 145 break 146 } 147 // update maxN & minN 148 if header.Time.Cmp(target) >= 0 { 149 if header.Number.Cmp(maxN) < 0 { 150 maxN.Set(header.Number) 151 } 152 } else if header.Time.Cmp(target) <= 0 { 153 if header.Number.Cmp(minN) > 0 { 154 minN.Set(header.Number) 155 } 156 } 157 158 } 159 } 160 return nil, errUnknownBlock 161 }