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  }