github.com/codingfuture/orig-energi3@v0.8.4/energi/api/checkpoints.go (about) 1 // Copyright 2019 The Energi Core Authors 2 // This file is part of the Energi Core library. 3 // 4 // The Energi Core 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 Energi Core 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 Energi Core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package api 18 19 import ( 20 "context" 21 "math/big" 22 23 "github.com/ethereum/go-ethereum/accounts" 24 "github.com/ethereum/go-ethereum/accounts/abi/bind" 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/log" 27 "github.com/ethereum/go-ethereum/rpc" 28 29 energi_abi "energi.world/core/gen3/energi/abi" 30 energi_common "energi.world/core/gen3/energi/common" 31 energi_params "energi.world/core/gen3/energi/params" 32 ) 33 34 type CheckpointAPI struct { 35 backend Backend 36 cpCache *energi_common.CacheStorage 37 } 38 39 func NewCheckpointAPI(b Backend) *CheckpointAPI { 40 r := &CheckpointAPI{ 41 backend: b, 42 cpCache: energi_common.NewCacheStorage(), 43 } 44 b.OnSyncedHeadUpdates(func() { 45 r.CheckpointInfo() 46 }) 47 return r 48 } 49 50 const ( 51 checkpointCallGas uint64 = 3000000 52 ) 53 54 func (b *CheckpointAPI) registry( 55 password *string, 56 from common.Address, 57 ) ( 58 session *energi_abi.ICheckpointRegistrySession, 59 hashsig func(common.Hash) ([]byte, error), 60 err error, 61 ) { 62 contract, err := energi_abi.NewICheckpointRegistry( 63 energi_params.Energi_CheckpointRegistry, b.backend.(bind.ContractBackend)) 64 if err != nil { 65 return nil, nil, err 66 } 67 68 hashsig = func(h common.Hash) ([]byte, error) { 69 account := accounts.Account{Address: from} 70 wallet, err := b.backend.AccountManager().Find(account) 71 if err != nil { 72 return nil, err 73 } 74 75 if password == nil { 76 return wallet.SignHash(account, h.Bytes()) 77 } 78 79 return wallet.SignHashWithPassphrase(account, *password, h.Bytes()) 80 } 81 82 session = &energi_abi.ICheckpointRegistrySession{ 83 Contract: contract, 84 CallOpts: bind.CallOpts{ 85 From: from, 86 GasLimit: energi_params.UnlimitedGas, 87 }, 88 TransactOpts: bind.TransactOpts{ 89 From: from, 90 Signer: createSignerCallback(b.backend, password), 91 GasLimit: checkpointCallGas, 92 }, 93 } 94 return 95 } 96 97 type CheckpointInfo struct { 98 Number uint64 99 Hash common.Hash 100 Since uint64 101 SigCount uint64 102 } 103 104 type AllCheckpointInfo struct { 105 Registry []CheckpointInfo 106 Active []CheckpointInfo 107 } 108 109 func (b *CheckpointAPI) CheckpointInfo() (res *AllCheckpointInfo, err error) { 110 var data interface{} 111 data, err = b.cpCache.Get(b.backend, b.checkpointInfo) 112 if err != nil || data == nil { 113 log.Error("CheckpointInfo failed", "err", err) 114 return 115 } 116 117 res = data.(*AllCheckpointInfo) 118 119 return 120 } 121 122 func (b *CheckpointAPI) checkpointInfo(num *big.Int) (interface{}, error) { 123 registry, err := energi_abi.NewICheckpointRegistryCaller( 124 energi_params.Energi_CheckpointRegistry, b.backend.(bind.ContractCaller)) 125 if err != nil { 126 log.Error("Failed", "err", err) 127 return nil, err 128 } 129 130 call_opts := &bind.CallOpts{ 131 BlockNumber: num, 132 GasLimit: energi_params.UnlimitedGas, 133 } 134 addresses, err := registry.Checkpoints(call_opts) 135 if err != nil { 136 log.Error("Failed", "err", err) 137 return nil, err 138 } 139 140 res := &AllCheckpointInfo{} 141 res.Registry = make([]CheckpointInfo, 0, len(addresses)) 142 143 for _, addr := range addresses { 144 cp, err := energi_abi.NewICheckpointV2Caller( 145 addr, b.backend.(bind.ContractCaller)) 146 if err != nil { 147 log.Error("Failed", "err", err) 148 continue 149 } 150 151 info, err := cp.Info(call_opts) 152 if err != nil { 153 log.Warn("Info error", "cp", addr, "err", err) 154 continue 155 } 156 157 sigs, err := cp.Signatures(call_opts) 158 if err != nil { 159 log.Warn("Proposals error", "addr", addr, "err", err) 160 continue 161 } 162 163 res.Registry = append(res.Registry, CheckpointInfo{ 164 Number: info.Number.Uint64(), 165 Hash: info.Hash, 166 Since: info.Since.Uint64(), 167 SigCount: uint64(len(sigs)), 168 }) 169 } 170 171 local := b.backend.ListCheckpoints() 172 res.Active = make([]CheckpointInfo, 0, len(local)) 173 174 for _, cp := range local { 175 res.Active = append(res.Active, CheckpointInfo{ 176 Number: cp.Number, 177 Hash: cp.Hash, 178 Since: cp.Since, 179 SigCount: cp.SigCount, 180 }) 181 } 182 183 return res, nil 184 } 185 186 func (b *CheckpointAPI) CheckpointPropose( 187 number uint64, 188 hash common.Hash, 189 password *string, 190 ) (txhash common.Hash, err error) { 191 if h, _ := b.backend.HeaderByNumber(context.Background(), rpc.BlockNumber(number)); h == nil { 192 log.Error("Block not found on local node", "number", number) 193 return 194 } else if h.Hash() != hash { 195 log.Error("Block mismatch on local node", "number", number, "hash", hash, "block", h.Hash()) 196 return 197 } 198 199 registry, hashsig, err := b.registry(password, b.backend.ChainConfig().Energi.CPPSigner) 200 if err != nil { 201 return 202 } 203 204 bnum := new(big.Int).SetUint64(number) 205 tosig, err := registry.SignatureBase(bnum, hash) 206 if err != nil { 207 return 208 } 209 210 sig, err := hashsig(tosig) 211 if err != nil { 212 return 213 } 214 215 // NOTE: compatibility with ecrecover opcode. 216 sig[64] += 27 217 218 tx, err := registry.Propose(bnum, hash, sig) 219 220 if tx != nil { 221 txhash = tx.Hash() 222 log.Info("Note: please wait until the proposal TX gets into a block!", "tx", txhash.Hex()) 223 } 224 225 return 226 } 227 228 type CheckpointAdminAPI struct { 229 backend Backend 230 } 231 232 func NewCheckpointAdminAPI(b Backend) *CheckpointAdminAPI { 233 return &CheckpointAdminAPI{b} 234 } 235 236 func (b *CheckpointAdminAPI) CheckpointLocal( 237 number uint64, 238 hash common.Hash, 239 ) error { 240 return b.backend.AddLocalCheckpoint(number, hash) 241 }