github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/consensus/bor/api.go (about)

     1  package bor
     2  
     3  import (
     4  	"encoding/hex"
     5  	"math"
     6  	"math/big"
     7  	"sort"
     8  	"strconv"
     9  	"sync"
    10  
    11  	"github.com/ethereum/go-ethereum/common"
    12  	"github.com/ethereum/go-ethereum/consensus"
    13  	"github.com/ethereum/go-ethereum/consensus/bor/valset"
    14  	"github.com/ethereum/go-ethereum/core/types"
    15  	"github.com/ethereum/go-ethereum/crypto"
    16  	"github.com/ethereum/go-ethereum/rpc"
    17  
    18  	lru "github.com/hashicorp/golang-lru"
    19  	"github.com/xsleonard/go-merkle"
    20  	"golang.org/x/crypto/sha3"
    21  )
    22  
    23  var (
    24  	// MaxCheckpointLength is the maximum number of blocks that can be requested for constructing a checkpoint root hash
    25  	MaxCheckpointLength = uint64(math.Pow(2, 15))
    26  )
    27  
    28  // API is a user facing RPC API to allow controlling the signer and voting
    29  // mechanisms of the proof-of-authority scheme.
    30  type API struct {
    31  	chain         consensus.ChainHeaderReader
    32  	bor           *Bor
    33  	rootHashCache *lru.ARCCache
    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  
    50  	return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    51  }
    52  
    53  type BlockSigners struct {
    54  	Signers []difficultiesKV
    55  	Diff    int
    56  	Author  common.Address
    57  }
    58  
    59  type difficultiesKV struct {
    60  	Signer     common.Address
    61  	Difficulty uint64
    62  }
    63  
    64  func rankMapDifficulties(values map[common.Address]uint64) []difficultiesKV {
    65  	ss := make([]difficultiesKV, 0, len(values))
    66  	for k, v := range values {
    67  		ss = append(ss, difficultiesKV{k, v})
    68  	}
    69  
    70  	sort.Slice(ss, func(i, j int) bool {
    71  		return ss[i].Difficulty > ss[j].Difficulty
    72  	})
    73  
    74  	return ss
    75  }
    76  
    77  // GetSnapshotProposerSequence retrieves the in-turn signers of all sprints in a span
    78  func (api *API) GetSnapshotProposerSequence(blockNrOrHash *rpc.BlockNumberOrHash) (BlockSigners, error) {
    79  	var header *types.Header
    80  	//nolint:nestif
    81  	if blockNrOrHash == nil {
    82  		header = api.chain.CurrentHeader()
    83  	} else {
    84  		if blockNr, ok := blockNrOrHash.Number(); ok {
    85  			if blockNr == rpc.LatestBlockNumber {
    86  				header = api.chain.CurrentHeader()
    87  			} else {
    88  				header = api.chain.GetHeaderByNumber(uint64(blockNr))
    89  			}
    90  		} else {
    91  			if blockHash, ok := blockNrOrHash.Hash(); ok {
    92  				header = api.chain.GetHeaderByHash(blockHash)
    93  			}
    94  		}
    95  	}
    96  
    97  	if header == nil {
    98  		return BlockSigners{}, errUnknownBlock
    99  	}
   100  
   101  	snapNumber := rpc.BlockNumber(header.Number.Int64() - 1)
   102  	snap, err := api.GetSnapshot(&snapNumber)
   103  
   104  	var difficulties = make(map[common.Address]uint64)
   105  
   106  	if err != nil {
   107  		return BlockSigners{}, err
   108  	}
   109  
   110  	proposer := snap.ValidatorSet.GetProposer().Address
   111  	proposerIndex, _ := snap.ValidatorSet.GetByAddress(proposer)
   112  
   113  	signers := snap.signers()
   114  	for i := 0; i < len(signers); i++ {
   115  		tempIndex := i
   116  		if tempIndex < proposerIndex {
   117  			tempIndex = tempIndex + len(signers)
   118  		}
   119  
   120  		difficulties[signers[i]] = uint64(len(signers) - (tempIndex - proposerIndex))
   121  	}
   122  
   123  	rankedDifficulties := rankMapDifficulties(difficulties)
   124  
   125  	author, err := api.GetAuthor(blockNrOrHash)
   126  	if err != nil {
   127  		return BlockSigners{}, err
   128  	}
   129  
   130  	diff := int(difficulties[*author])
   131  	blockSigners := &BlockSigners{
   132  		Signers: rankedDifficulties,
   133  		Diff:    diff,
   134  		Author:  *author,
   135  	}
   136  
   137  	return *blockSigners, nil
   138  }
   139  
   140  // GetSnapshotProposer retrieves the in-turn signer at a given block.
   141  func (api *API) GetSnapshotProposer(blockNrOrHash *rpc.BlockNumberOrHash) (common.Address, error) {
   142  	var header *types.Header
   143  	//nolint:nestif
   144  	if blockNrOrHash == nil {
   145  		header = api.chain.CurrentHeader()
   146  	} else {
   147  		if blockNr, ok := blockNrOrHash.Number(); ok {
   148  			if blockNr == rpc.LatestBlockNumber {
   149  				header = api.chain.CurrentHeader()
   150  			} else {
   151  				header = api.chain.GetHeaderByNumber(uint64(blockNr))
   152  			}
   153  		} else {
   154  			if blockHash, ok := blockNrOrHash.Hash(); ok {
   155  				header = api.chain.GetHeaderByHash(blockHash)
   156  			}
   157  		}
   158  	}
   159  
   160  	if header == nil {
   161  		return common.Address{}, errUnknownBlock
   162  	}
   163  
   164  	snapNumber := rpc.BlockNumber(header.Number.Int64() - 1)
   165  	snap, err := api.GetSnapshot(&snapNumber)
   166  
   167  	if err != nil {
   168  		return common.Address{}, err
   169  	}
   170  
   171  	return snap.ValidatorSet.GetProposer().Address, nil
   172  }
   173  
   174  // GetAuthor retrieves the author a block.
   175  func (api *API) GetAuthor(blockNrOrHash *rpc.BlockNumberOrHash) (*common.Address, error) {
   176  	// Retrieve the requested block number (or current if none requested)
   177  	var header *types.Header
   178  
   179  	//nolint:nestif
   180  	if blockNrOrHash == nil {
   181  		header = api.chain.CurrentHeader()
   182  	} else {
   183  		if blockNr, ok := blockNrOrHash.Number(); ok {
   184  			header = api.chain.GetHeaderByNumber(uint64(blockNr))
   185  			if blockNr == rpc.LatestBlockNumber {
   186  				header = api.chain.CurrentHeader()
   187  			}
   188  		} else {
   189  			if blockHash, ok := blockNrOrHash.Hash(); ok {
   190  				header = api.chain.GetHeaderByHash(blockHash)
   191  			}
   192  		}
   193  	}
   194  
   195  	// Ensure we have an actually valid block and return its snapshot
   196  	if header == nil {
   197  		return nil, errUnknownBlock
   198  	}
   199  
   200  	author, err := api.bor.Author(header)
   201  
   202  	return &author, err
   203  }
   204  
   205  // GetSnapshotAtHash retrieves the state snapshot at a given block.
   206  func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
   207  	header := api.chain.GetHeaderByHash(hash)
   208  	if header == nil {
   209  		return nil, errUnknownBlock
   210  	}
   211  
   212  	return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
   213  }
   214  
   215  // GetSigners retrieves the list of authorized signers at the specified block.
   216  func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
   217  	// Retrieve the requested block number (or current if none requested)
   218  	var header *types.Header
   219  	if number == nil || *number == rpc.LatestBlockNumber {
   220  		header = api.chain.CurrentHeader()
   221  	} else {
   222  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
   223  	}
   224  	// Ensure we have an actually valid block and return the signers from its snapshot
   225  	if header == nil {
   226  		return nil, errUnknownBlock
   227  	}
   228  
   229  	snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
   230  
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  
   235  	return snap.signers(), nil
   236  }
   237  
   238  // GetSignersAtHash retrieves the list of authorized signers at the specified block.
   239  func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
   240  	header := api.chain.GetHeaderByHash(hash)
   241  	if header == nil {
   242  		return nil, errUnknownBlock
   243  	}
   244  
   245  	snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
   246  
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  
   251  	return snap.signers(), nil
   252  }
   253  
   254  // GetCurrentProposer gets the current proposer
   255  func (api *API) GetCurrentProposer() (common.Address, error) {
   256  	snap, err := api.GetSnapshot(nil)
   257  	if err != nil {
   258  		return common.Address{}, err
   259  	}
   260  
   261  	return snap.ValidatorSet.GetProposer().Address, nil
   262  }
   263  
   264  // GetCurrentValidators gets the current validators
   265  func (api *API) GetCurrentValidators() ([]*valset.Validator, error) {
   266  	snap, err := api.GetSnapshot(nil)
   267  	if err != nil {
   268  		return make([]*valset.Validator, 0), err
   269  	}
   270  
   271  	return snap.ValidatorSet.Validators, nil
   272  }
   273  
   274  // GetRootHash returns the merkle root of the start to end block headers
   275  func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
   276  	if err := api.initializeRootHashCache(); err != nil {
   277  		return "", err
   278  	}
   279  
   280  	key := getRootHashKey(start, end)
   281  
   282  	if root, known := api.rootHashCache.Get(key); known {
   283  		return root.(string), nil
   284  	}
   285  
   286  	length := end - start + 1
   287  
   288  	if length > MaxCheckpointLength {
   289  		return "", &MaxCheckpointLengthExceededError{start, end}
   290  	}
   291  
   292  	currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64()
   293  
   294  	if start > end || end > currentHeaderNumber {
   295  		return "", &valset.InvalidStartEndBlockError{Start: start, End: end, CurrentHeader: currentHeaderNumber}
   296  	}
   297  
   298  	blockHeaders := make([]*types.Header, end-start+1)
   299  	wg := new(sync.WaitGroup)
   300  	concurrent := make(chan bool, 20)
   301  
   302  	for i := start; i <= end; i++ {
   303  		wg.Add(1)
   304  		concurrent <- true
   305  
   306  		go func(number uint64) {
   307  			blockHeaders[number-start] = api.chain.GetHeaderByNumber(number)
   308  
   309  			<-concurrent
   310  			wg.Done()
   311  		}(i)
   312  	}
   313  	wg.Wait()
   314  	close(concurrent)
   315  
   316  	headers := make([][32]byte, nextPowerOfTwo(length))
   317  
   318  	for i := 0; i < len(blockHeaders); i++ {
   319  		blockHeader := blockHeaders[i]
   320  		header := crypto.Keccak256(appendBytes32(
   321  			blockHeader.Number.Bytes(),
   322  			new(big.Int).SetUint64(blockHeader.Time).Bytes(),
   323  			blockHeader.TxHash.Bytes(),
   324  			blockHeader.ReceiptHash.Bytes(),
   325  		))
   326  
   327  		var arr [32]byte
   328  
   329  		copy(arr[:], header)
   330  		headers[i] = arr
   331  	}
   332  
   333  	tree := merkle.NewTreeWithOpts(merkle.TreeOptions{EnableHashSorting: false, DisableHashLeaves: true})
   334  	if err := tree.Generate(convert(headers), sha3.NewLegacyKeccak256()); err != nil {
   335  		return "", err
   336  	}
   337  
   338  	root := hex.EncodeToString(tree.Root().Hash)
   339  	api.rootHashCache.Add(key, root)
   340  
   341  	return root, nil
   342  }
   343  
   344  func (api *API) initializeRootHashCache() error {
   345  	var err error
   346  	if api.rootHashCache == nil {
   347  		api.rootHashCache, err = lru.NewARC(10)
   348  	}
   349  
   350  	return err
   351  }
   352  
   353  func getRootHashKey(start uint64, end uint64) string {
   354  	return strconv.FormatUint(start, 10) + "-" + strconv.FormatUint(end, 10)
   355  }