github.com/elastos/Elastos.ELA.SideChain.ETH@v0.2.2/chainbridge-core/chains/evm/voter/voter.go (about) 1 // Copyright 2021 ChainSafe Systems 2 // SPDX-License-Identifier: LGPL-3.0-only 3 4 package voter 5 6 import ( 7 "bytes" 8 "context" 9 "errors" 10 "math/big" 11 12 "github.com/elastos/Elastos.ELA.SideChain.ESC" 13 "github.com/elastos/Elastos.ELA.SideChain.ESC/accounts" 14 "github.com/elastos/Elastos.ELA.SideChain.ESC/chainbridge-core/bridgelog" 15 "github.com/elastos/Elastos.ELA.SideChain.ESC/chainbridge-core/chains/evm/evmclient" 16 "github.com/elastos/Elastos.ELA.SideChain.ESC/chainbridge-core/chains/evm/evmtransaction" 17 "github.com/elastos/Elastos.ELA.SideChain.ESC/chainbridge-core/crypto/secp256k1" 18 "github.com/elastos/Elastos.ELA.SideChain.ESC/chainbridge-core/engine" 19 "github.com/elastos/Elastos.ELA.SideChain.ESC/chainbridge_abi" 20 "github.com/elastos/Elastos.ELA.SideChain.ESC/common" 21 "github.com/elastos/Elastos.ELA.SideChain.ESC/common/hexutil" 22 "github.com/elastos/Elastos.ELA.SideChain.ESC/core/types" 23 "github.com/elastos/Elastos.ELA.SideChain.ESC/crypto" 24 "github.com/elastos/Elastos.ELA.SideChain.ESC/internal/ethapi" 25 "github.com/elastos/Elastos.ELA.SideChain.ESC/log" 26 ) 27 28 type ChainClient interface { 29 LatestBlock() (*big.Int, error) 30 CurrentBlock() (*types.Block, error) 31 SignAndSendTransaction(ctx context.Context, tx evmclient.CommonTransaction) (common.Hash, error) 32 CallContract(ctx context.Context, callArgs map[string]interface{}, blockNumber *big.Int) ([]byte, error) 33 GetNonce() (*big.Int, error) 34 LockNonce() 35 UnlockNonce() 36 GasPrice() (*big.Int, error) 37 EstimateGasLimit(ctx context.Context, msg ethereum.CallMsg) (uint64, error) 38 ChainID(ctx context.Context) (*big.Int, error) 39 Engine() engine.ESCEngine 40 GetClientAddress() common.Address 41 IsContractAddress(address string) bool 42 PendingTransaction() ([]ethapi.RPCTransaction, error) 43 } 44 45 type EVMVoter struct { 46 stop <-chan struct{} 47 client ChainClient 48 account *secp256k1.Keypair 49 } 50 51 func NewVoter(client ChainClient, arbiterAccount *secp256k1.Keypair) *EVMVoter { 52 return &EVMVoter{ 53 client: client, 54 account: arbiterAccount, 55 } 56 } 57 58 func (w *EVMVoter) GetPublicKey() ([]byte, error) { 59 if w.account == nil { 60 return nil, errors.New("account is nil") 61 } 62 pbk, err := hexutil.Decode(w.account.PublicKey()) 63 return pbk, err 64 } 65 66 func (w *EVMVoter) GetSignerAddress() (common.Address, error) { 67 if w.account == nil { 68 return common.Address{}, errors.New("account is nil") 69 } 70 return w.account.CommonAddress(), nil 71 } 72 73 func (w *EVMVoter) SetArbiterList(arbiters []common.Address, totalCount int, signature [][]byte, bridgeAddress string) error { 74 a, err := chainbridge_abi.GetSetArbitersABI() 75 if err != nil { 76 return err 77 } 78 gasPrice, err := w.client.GasPrice() 79 if err != nil { 80 log.Error("SetArbiterList GasPrice", "error", err) 81 return err 82 } 83 count := big.NewInt(int64(totalCount)) 84 input, err := a.Pack("setArbiterList", arbiters, &count, signature) 85 if err != nil { 86 return err 87 } 88 pendingTx, _ := w.client.PendingTransaction() 89 for _, tx := range pendingTx { 90 if tx.To.String() == bridgeAddress && bytes.Compare(tx.Input, input) == 0 { 91 bridgelog.Info("is pending tx") 92 return nil 93 } 94 } 95 96 bridge := common.HexToAddress(bridgeAddress) 97 from := w.client.GetClientAddress() 98 msg := ethereum.CallMsg{From: from, To: &bridge, Data: input, GasPrice: gasPrice} 99 gasLimit, err := w.client.EstimateGasLimit(context.TODO(), msg) 100 if err != nil { 101 log.Error("SetArbiterList EstimateGasLimit", "error", err) 102 return err 103 } 104 if gasLimit == 0 { 105 return errors.New("SetArbiterList EstimateGasLimit is 0") 106 } 107 w.client.LockNonce() 108 defer w.client.UnlockNonce() 109 n, err := w.client.GetNonce() 110 if err != nil { 111 log.Error("SetArbiterList GetNonce", "error", err) 112 return err 113 } 114 115 tx := evmtransaction.NewTransaction(n.Uint64(), bridge, big.NewInt(0), gasLimit, gasPrice, input) 116 hash, err := w.client.SignAndSendTransaction(context.TODO(), tx) 117 if err != nil { 118 log.Error("SetArbiterList SignAndSendTransaction", "error", err) 119 return err 120 } 121 log.Info("SetArbiterList", "error", err, "hash", hash.String()) 122 return err 123 } 124 125 func (w *EVMVoter) GetArbiterList(bridgeAddress string) ([]common.Address, error) { 126 a, err := chainbridge_abi.GetArbitersABI() 127 if err != nil { 128 return []common.Address{}, err 129 } 130 input, err := a.Pack("getArbiterList") 131 if err != nil { 132 return []common.Address{}, err 133 } 134 bridge := common.HexToAddress(bridgeAddress) 135 msg := ethereum.CallMsg{From: common.Address{}, To: &bridge, Data: input} 136 out, err := w.client.CallContract(context.TODO(), toCallArg(msg), nil) 137 log.Info("getArbiterList", "error", err, "out", out) 138 139 out0 := make([]common.Address, 0) 140 err = a.Unpack(&out0, "getArbiterList", out) 141 if err != nil { 142 return []common.Address{}, err 143 } 144 return out0, err 145 } 146 147 func (w *EVMVoter) SetESCState(bridgeAddress string, state uint8) error { 148 gasPrice, err := w.client.GasPrice() 149 if err != nil { 150 return err 151 } 152 stateValue := big.NewInt(0).SetUint64(uint64(state)) 153 packData := common.LeftPadBytes(stateValue.Bytes(), 32) 154 a, err := chainbridge_abi.SetESCStateABI() 155 if err != nil { 156 return err 157 } 158 khash := crypto.Keccak256(packData) 159 signature := w.SignData(accounts.TextHash(khash)) 160 input, err := a.Pack("setChainStatus", state, signature) 161 if err != nil { 162 return err 163 } 164 bridge := common.HexToAddress(bridgeAddress) 165 from := w.client.GetClientAddress() 166 msg := ethereum.CallMsg{From: from, To: &bridge, Data: input, GasPrice: gasPrice} 167 gasLimit, err := w.client.EstimateGasLimit(context.TODO(), msg) 168 if err != nil { 169 return err 170 } 171 if gasLimit == 0 { 172 return errors.New("SetESCState EstimateGasLimit is 0") 173 } 174 w.client.LockNonce() 175 defer w.client.UnlockNonce() 176 n, err := w.client.GetNonce() 177 if err != nil { 178 return err 179 } 180 gasLimit = gasLimit * 3 181 tx := evmtransaction.NewTransaction(n.Uint64(), bridge, big.NewInt(0), gasLimit, gasPrice, input) 182 hash, err := w.client.SignAndSendTransaction(context.TODO(), tx) 183 if err != nil { 184 return err 185 } 186 log.Info("SetESCState", "error", err, "hash", hash.String(), "gasLimit", gasLimit, "gasPrice", gasPrice) 187 return err 188 } 189 190 func (w *EVMVoter) SetManualArbiter(bridgeAddress string, arbiters []common.Address, totalSigner int) error { 191 gasPrice, err := w.client.GasPrice() 192 if err != nil { 193 return err 194 } 195 a, err := chainbridge_abi.SetManualArbiterABI() 196 if err != nil { 197 return err 198 } 199 200 data := make([]byte, 0) 201 for _, arbiter := range arbiters { 202 data = append(data, arbiter.Bytes()...) 203 } 204 totalCount := big.NewInt(0).SetUint64(uint64(totalSigner)) 205 totalBytes := common.LeftPadBytes(totalCount.Bytes(), 32) 206 data = append(data, totalBytes...) 207 khash := crypto.Keccak256(data) 208 signature := w.SignData(accounts.TextHash(khash)) 209 input, err := a.Pack("setManualArbiter", arbiters, &totalCount, signature) 210 if err != nil { 211 return err 212 } 213 bridge := common.HexToAddress(bridgeAddress) 214 from := w.client.GetClientAddress() 215 msg := ethereum.CallMsg{From: from, To: &bridge, Data: input, GasPrice: gasPrice} 216 gasLimit, err := w.client.EstimateGasLimit(context.TODO(), msg) 217 if err != nil { 218 return err 219 } 220 if gasLimit == 0 { 221 return errors.New("setManualArbiter EstimateGasLimit is 0") 222 } 223 w.client.LockNonce() 224 defer w.client.UnlockNonce() 225 n, err := w.client.GetNonce() 226 if err != nil { 227 return err 228 } 229 gasLimit = gasLimit * 4 230 tx := evmtransaction.NewTransaction(n.Uint64(), bridge, big.NewInt(0), gasLimit, gasPrice, input) 231 hash, err := w.client.SignAndSendTransaction(context.TODO(), tx) 232 if err != nil { 233 return err 234 } 235 log.Info("setManualArbiter", "error", err, "hash", hash.String(), "gasLimit", gasLimit, "gasPrice", gasPrice) 236 return err 237 } 238 239 func (w *EVMVoter) GetSignatures(bridgeAddress string) ([][crypto.SignatureLength]byte, error) { 240 a, err := chainbridge_abi.GetSignaturesABI() 241 if err != nil { 242 return [][crypto.SignatureLength]byte{}, err 243 } 244 input, err := a.Pack("getArbiterSigs") 245 if err != nil { 246 return [][crypto.SignatureLength]byte{}, err 247 } 248 bridge := common.HexToAddress(bridgeAddress) 249 msg := ethereum.CallMsg{From: common.Address{}, To: &bridge, Data: input} 250 out, err := w.client.CallContract(context.TODO(), toCallArg(msg), nil) 251 log.Info("getArbiterSigs", "error", err, "out", out) 252 253 out0 := make([][crypto.SignatureLength]byte, 0) 254 err = a.Unpack(&out0, "getArbiterSigs", out) 255 if err != nil { 256 return [][crypto.SignatureLength]byte{}, err 257 } 258 return out0, err 259 } 260 261 func (w *EVMVoter) GetTotalCount(bridgeAddress string) (uint64, error) { 262 a, err := chainbridge_abi.GetTotalCountABI() 263 if err != nil { 264 return 0, err 265 } 266 input, err := a.Pack("getArbiterCount") 267 if err != nil { 268 return 0, err 269 } 270 bridge := common.HexToAddress(bridgeAddress) 271 msg := ethereum.CallMsg{From: common.Address{}, To: &bridge, Data: input} 272 out, err := w.client.CallContract(context.TODO(), toCallArg(msg), nil) 273 log.Info("getArbiterCount", "error", err, "out", out) 274 275 out0 := big.NewInt(0).SetBytes(out) 276 err = a.Unpack(&out0, "getArbiterCount", out) 277 if err != nil { 278 return 0, err 279 } 280 return out0.Uint64(), err 281 } 282 283 func (w *EVMVoter) GetESCState(bridgeAddress string) (uint8, error) { 284 a, err := chainbridge_abi.GetESCStateABI() 285 if err != nil { 286 return 0, err 287 } 288 input, err := a.Pack("getESCChainState") 289 if err != nil { 290 return 0, err 291 } 292 bridge := common.HexToAddress(bridgeAddress) 293 msg := ethereum.CallMsg{From: common.Address{}, To: &bridge, Data: input} 294 out, err := w.client.CallContract(context.TODO(), toCallArg(msg), nil) 295 log.Info("GetESCState", "error", err, "out", out) 296 297 out0 := big.NewInt(0).SetBytes(out) 298 return uint8(out0.Uint64()), err 299 } 300 301 func (w *EVMVoter) GetHashSalt(bridgeAddress string) (*big.Int, error) { 302 a, err := chainbridge_abi.GetHashSaltABI() 303 if err != nil { 304 return big.NewInt(0), err 305 } 306 input, err := a.Pack("GetHashSalt") 307 if err != nil { 308 return big.NewInt(0), err 309 } 310 bridge := common.HexToAddress(bridgeAddress) 311 msg := ethereum.CallMsg{From: common.Address{}, To: &bridge, Data: input} 312 out, err := w.client.CallContract(context.TODO(), toCallArg(msg), nil) 313 log.Info("GetHashSalt", "error", err, "out", out) 314 315 out0 := big.NewInt(0).SetBytes(out) 316 return out0, err 317 } 318 319 func (w *EVMVoter) IsDeployedBridgeContract(bridgeAddress string) bool { 320 return w.client.IsContractAddress(bridgeAddress) 321 } 322 323 func (w *EVMVoter) GetClient() ChainClient { 324 return w.client 325 } 326 327 func (w *EVMVoter) SignData(data []byte) []byte { 328 privateKey := w.account.PrivateKey() 329 sign, err := crypto.Sign(data, privateKey) 330 if err != nil { 331 return nil 332 } 333 return sign 334 } 335 336 func toCallArg(msg ethereum.CallMsg) map[string]interface{} { 337 arg := map[string]interface{}{ 338 "from": msg.From, 339 "to": msg.To, 340 } 341 if len(msg.Data) > 0 { 342 arg["data"] = hexutil.Bytes(msg.Data) 343 } 344 if msg.Value != nil { 345 arg["value"] = (*hexutil.Big)(msg.Value) 346 } 347 if msg.Gas != 0 { 348 arg["gas"] = hexutil.Uint64(msg.Gas) 349 } 350 if msg.GasPrice != nil { 351 arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice) 352 } 353 return arg 354 }