github.com/ImPedro29/bor@v0.2.7/consensus/bor/api.go (about)

     1  package bor
     2  
     3  import (
     4  	"encoding/hex"
     5  	"math"
     6  	"math/big"
     7  	"strconv"
     8  	"sync"
     9  
    10  	"github.com/ethereum/go-ethereum/common"
    11  	"github.com/ethereum/go-ethereum/consensus"
    12  	"github.com/ethereum/go-ethereum/core/types"
    13  	"github.com/ethereum/go-ethereum/crypto"
    14  	"github.com/ethereum/go-ethereum/rpc"
    15  	lru "github.com/hashicorp/golang-lru"
    16  	"github.com/xsleonard/go-merkle"
    17  	"golang.org/x/crypto/sha3"
    18  )
    19  
    20  var (
    21  	// MaxCheckpointLength is the maximum number of blocks that can be requested for constructing a checkpoint root hash
    22  	MaxCheckpointLength = uint64(math.Pow(2, 15))
    23  )
    24  
    25  // API is a user facing RPC API to allow controlling the signer and voting
    26  // mechanisms of the proof-of-authority scheme.
    27  type API struct {
    28  	chain         consensus.ChainHeaderReader
    29  	bor           *Bor
    30  	rootHashCache *lru.ARCCache
    31  }
    32  
    33  // GetSnapshot retrieves the state snapshot at a given block.
    34  func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
    35  	// Retrieve the requested block number (or current if none requested)
    36  	var header *types.Header
    37  	if number == nil || *number == rpc.LatestBlockNumber {
    38  		header = api.chain.CurrentHeader()
    39  	} else {
    40  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
    41  	}
    42  	// Ensure we have an actually valid block and return its snapshot
    43  	if header == nil {
    44  		return nil, errUnknownBlock
    45  	}
    46  	return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    47  }
    48  
    49  // GetAuthor retrieves the author a block.
    50  func (api *API) GetAuthor(number *rpc.BlockNumber) (*common.Address, error) {
    51  	// Retrieve the requested block number (or current if none requested)
    52  	var header *types.Header
    53  	if number == nil || *number == rpc.LatestBlockNumber {
    54  		header = api.chain.CurrentHeader()
    55  	} else {
    56  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
    57  	}
    58  	// Ensure we have an actually valid block and return its snapshot
    59  	if header == nil {
    60  		return nil, errUnknownBlock
    61  	}
    62  	author, err := api.bor.Author(header)
    63  	return &author, err
    64  }
    65  
    66  // GetSnapshotAtHash retrieves the state snapshot at a given block.
    67  func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
    68  	header := api.chain.GetHeaderByHash(hash)
    69  	if header == nil {
    70  		return nil, errUnknownBlock
    71  	}
    72  	return api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    73  }
    74  
    75  // GetSigners retrieves the list of authorized signers at the specified block.
    76  func (api *API) GetSigners(number *rpc.BlockNumber) ([]common.Address, error) {
    77  	// Retrieve the requested block number (or current if none requested)
    78  	var header *types.Header
    79  	if number == nil || *number == rpc.LatestBlockNumber {
    80  		header = api.chain.CurrentHeader()
    81  	} else {
    82  		header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
    83  	}
    84  	// Ensure we have an actually valid block and return the signers from its snapshot
    85  	if header == nil {
    86  		return nil, errUnknownBlock
    87  	}
    88  	snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	return snap.signers(), nil
    93  }
    94  
    95  // GetSignersAtHash retrieves the list of authorized signers at the specified block.
    96  func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
    97  	header := api.chain.GetHeaderByHash(hash)
    98  	if header == nil {
    99  		return nil, errUnknownBlock
   100  	}
   101  	snap, err := api.bor.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  	return snap.signers(), nil
   106  }
   107  
   108  // GetCurrentProposer gets the current proposer
   109  func (api *API) GetCurrentProposer() (common.Address, error) {
   110  	snap, err := api.GetSnapshot(nil)
   111  	if err != nil {
   112  		return common.Address{}, err
   113  	}
   114  	return snap.ValidatorSet.GetProposer().Address, nil
   115  }
   116  
   117  // GetCurrentValidators gets the current validators
   118  func (api *API) GetCurrentValidators() ([]*Validator, error) {
   119  	snap, err := api.GetSnapshot(nil)
   120  	if err != nil {
   121  		return make([]*Validator, 0), err
   122  	}
   123  	return snap.ValidatorSet.Validators, nil
   124  }
   125  
   126  // GetRootHash returns the merkle root of the start to end block headers
   127  func (api *API) GetRootHash(start uint64, end uint64) (string, error) {
   128  	if err := api.initializeRootHashCache(); err != nil {
   129  		return "", err
   130  	}
   131  	key := getRootHashKey(start, end)
   132  	if root, known := api.rootHashCache.Get(key); known {
   133  		return root.(string), nil
   134  	}
   135  	length := uint64(end - start + 1)
   136  	if length > MaxCheckpointLength {
   137  		return "", &MaxCheckpointLengthExceededError{start, end}
   138  	}
   139  	currentHeaderNumber := api.chain.CurrentHeader().Number.Uint64()
   140  	if start > end || end > currentHeaderNumber {
   141  		return "", &InvalidStartEndBlockError{start, end, currentHeaderNumber}
   142  	}
   143  	blockHeaders := make([]*types.Header, end-start+1)
   144  	wg := new(sync.WaitGroup)
   145  	concurrent := make(chan bool, 20)
   146  	for i := start; i <= end; i++ {
   147  		wg.Add(1)
   148  		concurrent <- true
   149  		go func(number uint64) {
   150  			blockHeaders[number-start] = api.chain.GetHeaderByNumber(uint64(number))
   151  			<-concurrent
   152  			wg.Done()
   153  		}(i)
   154  	}
   155  	wg.Wait()
   156  	close(concurrent)
   157  
   158  	headers := make([][32]byte, nextPowerOfTwo(length))
   159  	for i := 0; i < len(blockHeaders); i++ {
   160  		blockHeader := blockHeaders[i]
   161  		header := crypto.Keccak256(appendBytes32(
   162  			blockHeader.Number.Bytes(),
   163  			new(big.Int).SetUint64(blockHeader.Time).Bytes(),
   164  			blockHeader.TxHash.Bytes(),
   165  			blockHeader.ReceiptHash.Bytes(),
   166  		))
   167  
   168  		var arr [32]byte
   169  		copy(arr[:], header)
   170  		headers[i] = arr
   171  	}
   172  
   173  	tree := merkle.NewTreeWithOpts(merkle.TreeOptions{EnableHashSorting: false, DisableHashLeaves: true})
   174  	if err := tree.Generate(convert(headers), sha3.NewLegacyKeccak256()); err != nil {
   175  		return "", err
   176  	}
   177  	root := hex.EncodeToString(tree.Root().Hash)
   178  	api.rootHashCache.Add(key, root)
   179  	return root, nil
   180  }
   181  
   182  func (api *API) initializeRootHashCache() error {
   183  	var err error
   184  	if api.rootHashCache == nil {
   185  		api.rootHashCache, err = lru.NewARC(10)
   186  	}
   187  	return err
   188  }
   189  
   190  func getRootHashKey(start uint64, end uint64) string {
   191  	return strconv.FormatUint(start, 10) + "-" + strconv.FormatUint(end, 10)
   192  }