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  }