github.com/theQRL/go-zond@v0.1.1/cmd/devp2p/internal/ethtest/chain.go (about)

     1  // Copyright 2020 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU 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  // go-ethereum 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 General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package ethtest
    18  
    19  import (
    20  	"compress/gzip"
    21  	"encoding/json"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"math/big"
    26  	"os"
    27  	"strings"
    28  
    29  	"github.com/theQRL/go-zond/common"
    30  	"github.com/theQRL/go-zond/core"
    31  	"github.com/theQRL/go-zond/core/forkid"
    32  	"github.com/theQRL/go-zond/core/types"
    33  	"github.com/theQRL/go-zond/params"
    34  	"github.com/theQRL/go-zond/rlp"
    35  )
    36  
    37  type Chain struct {
    38  	genesis     core.Genesis
    39  	blocks      []*types.Block
    40  	chainConfig *params.ChainConfig
    41  }
    42  
    43  // Len returns the length of the chain.
    44  func (c *Chain) Len() int {
    45  	return len(c.blocks)
    46  }
    47  
    48  // TD calculates the total difficulty of the chain at the
    49  // chain head.
    50  func (c *Chain) TD() *big.Int {
    51  	sum := new(big.Int)
    52  	for _, block := range c.blocks[:c.Len()] {
    53  		sum.Add(sum, block.Difficulty())
    54  	}
    55  	return sum
    56  }
    57  
    58  // TotalDifficultyAt calculates the total difficulty of the chain
    59  // at the given block height.
    60  func (c *Chain) TotalDifficultyAt(height int) *big.Int {
    61  	sum := new(big.Int)
    62  	if height >= c.Len() {
    63  		return sum
    64  	}
    65  	for _, block := range c.blocks[:height+1] {
    66  		sum.Add(sum, block.Difficulty())
    67  	}
    68  	return sum
    69  }
    70  
    71  func (c *Chain) RootAt(height int) common.Hash {
    72  	if height < c.Len() {
    73  		return c.blocks[height].Root()
    74  	}
    75  	return common.Hash{}
    76  }
    77  
    78  // ForkID gets the fork id of the chain.
    79  func (c *Chain) ForkID() forkid.ID {
    80  	return forkid.NewID(c.chainConfig, c.blocks[0], uint64(c.Len()), c.blocks[0].Time())
    81  }
    82  
    83  // Shorten returns a copy chain of a desired height from the imported
    84  func (c *Chain) Shorten(height int) *Chain {
    85  	blocks := make([]*types.Block, height)
    86  	copy(blocks, c.blocks[:height])
    87  
    88  	config := *c.chainConfig
    89  	return &Chain{
    90  		blocks:      blocks,
    91  		chainConfig: &config,
    92  	}
    93  }
    94  
    95  // Head returns the chain head.
    96  func (c *Chain) Head() *types.Block {
    97  	return c.blocks[c.Len()-1]
    98  }
    99  
   100  func (c *Chain) GetHeaders(req *GetBlockHeaders) ([]*types.Header, error) {
   101  	if req.Amount < 1 {
   102  		return nil, errors.New("no block headers requested")
   103  	}
   104  
   105  	headers := make([]*types.Header, req.Amount)
   106  	var blockNumber uint64
   107  
   108  	// range over blocks to check if our chain has the requested header
   109  	for _, block := range c.blocks {
   110  		if block.Hash() == req.Origin.Hash || block.Number().Uint64() == req.Origin.Number {
   111  			headers[0] = block.Header()
   112  			blockNumber = block.Number().Uint64()
   113  		}
   114  	}
   115  	if headers[0] == nil {
   116  		return nil, fmt.Errorf("no headers found for given origin number %v, hash %v", req.Origin.Number, req.Origin.Hash)
   117  	}
   118  
   119  	if req.Reverse {
   120  		for i := 1; i < int(req.Amount); i++ {
   121  			blockNumber -= (1 - req.Skip)
   122  			headers[i] = c.blocks[blockNumber].Header()
   123  		}
   124  
   125  		return headers, nil
   126  	}
   127  
   128  	for i := 1; i < int(req.Amount); i++ {
   129  		blockNumber += (1 + req.Skip)
   130  		headers[i] = c.blocks[blockNumber].Header()
   131  	}
   132  
   133  	return headers, nil
   134  }
   135  
   136  // loadChain takes the given chain.rlp file, and decodes and returns
   137  // the blocks from the file.
   138  func loadChain(chainfile string, genesis string) (*Chain, error) {
   139  	gen, err := loadGenesis(genesis)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  	gblock := gen.ToBlock()
   144  
   145  	blocks, err := blocksFromFile(chainfile, gblock)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	c := &Chain{genesis: gen, blocks: blocks, chainConfig: gen.Config}
   151  	return c, nil
   152  }
   153  
   154  func loadGenesis(genesisFile string) (core.Genesis, error) {
   155  	chainConfig, err := os.ReadFile(genesisFile)
   156  	if err != nil {
   157  		return core.Genesis{}, err
   158  	}
   159  	var gen core.Genesis
   160  	if err := json.Unmarshal(chainConfig, &gen); err != nil {
   161  		return core.Genesis{}, err
   162  	}
   163  	return gen, nil
   164  }
   165  
   166  func blocksFromFile(chainfile string, gblock *types.Block) ([]*types.Block, error) {
   167  	// Load chain.rlp.
   168  	fh, err := os.Open(chainfile)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  	defer fh.Close()
   173  	var reader io.Reader = fh
   174  	if strings.HasSuffix(chainfile, ".gz") {
   175  		if reader, err = gzip.NewReader(reader); err != nil {
   176  			return nil, err
   177  		}
   178  	}
   179  	stream := rlp.NewStream(reader, 0)
   180  	var blocks = make([]*types.Block, 1)
   181  	blocks[0] = gblock
   182  	for i := 0; ; i++ {
   183  		var b types.Block
   184  		if err := stream.Decode(&b); err == io.EOF {
   185  			break
   186  		} else if err != nil {
   187  			return nil, fmt.Errorf("at block index %d: %v", i, err)
   188  		}
   189  		if b.NumberU64() != uint64(i+1) {
   190  			return nil, fmt.Errorf("block at index %d has wrong number %d", i, b.NumberU64())
   191  		}
   192  		blocks = append(blocks, &b)
   193  	}
   194  	return blocks, nil
   195  }