chain.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright 2020 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package ethtest
  17. import (
  18. "compress/gzip"
  19. "encoding/json"
  20. "fmt"
  21. "io"
  22. "io/ioutil"
  23. "math/big"
  24. "os"
  25. "strings"
  26. "github.com/ethereum/go-ethereum/core"
  27. "github.com/ethereum/go-ethereum/core/forkid"
  28. "github.com/ethereum/go-ethereum/core/types"
  29. "github.com/ethereum/go-ethereum/params"
  30. "github.com/ethereum/go-ethereum/rlp"
  31. )
  32. type Chain struct {
  33. blocks []*types.Block
  34. chainConfig *params.ChainConfig
  35. }
  36. func (c *Chain) WriteTo(writer io.Writer) error {
  37. for _, block := range c.blocks {
  38. if err := rlp.Encode(writer, block); err != nil {
  39. return err
  40. }
  41. }
  42. return nil
  43. }
  44. // Len returns the length of the chain.
  45. func (c *Chain) Len() int {
  46. return len(c.blocks)
  47. }
  48. // TD calculates the total difficulty of the chain.
  49. func (c *Chain) TD(height int) *big.Int { // TODO later on channge scheme so that the height is included in range
  50. sum := big.NewInt(0)
  51. for _, block := range c.blocks[:height] {
  52. sum.Add(sum, block.Difficulty())
  53. }
  54. return sum
  55. }
  56. // ForkID gets the fork id of the chain.
  57. func (c *Chain) ForkID() forkid.ID {
  58. return forkid.NewID(c.chainConfig, c.blocks[0].Hash(), uint64(c.Len()))
  59. }
  60. // Shorten returns a copy chain of a desired height from the imported
  61. func (c *Chain) Shorten(height int) *Chain {
  62. blocks := make([]*types.Block, height)
  63. copy(blocks, c.blocks[:height])
  64. config := *c.chainConfig
  65. return &Chain{
  66. blocks: blocks,
  67. chainConfig: &config,
  68. }
  69. }
  70. // Head returns the chain head.
  71. func (c *Chain) Head() *types.Block {
  72. return c.blocks[c.Len()-1]
  73. }
  74. func (c *Chain) GetHeaders(req GetBlockHeaders) (BlockHeaders, error) {
  75. if req.Amount < 1 {
  76. return nil, fmt.Errorf("no block headers requested")
  77. }
  78. headers := make(BlockHeaders, req.Amount)
  79. var blockNumber uint64
  80. // range over blocks to check if our chain has the requested header
  81. for _, block := range c.blocks {
  82. if block.Hash() == req.Origin.Hash || block.Number().Uint64() == req.Origin.Number {
  83. headers[0] = block.Header()
  84. blockNumber = block.Number().Uint64()
  85. }
  86. }
  87. if headers[0] == nil {
  88. return nil, fmt.Errorf("no headers found for given origin number %v, hash %v", req.Origin.Number, req.Origin.Hash)
  89. }
  90. if req.Reverse {
  91. for i := 1; i < int(req.Amount); i++ {
  92. blockNumber -= (1 - req.Skip)
  93. headers[i] = c.blocks[blockNumber].Header()
  94. }
  95. return headers, nil
  96. }
  97. for i := 1; i < int(req.Amount); i++ {
  98. blockNumber += (1 + req.Skip)
  99. headers[i] = c.blocks[blockNumber].Header()
  100. }
  101. return headers, nil
  102. }
  103. // loadChain takes the given chain.rlp file, and decodes and returns
  104. // the blocks from the file.
  105. func loadChain(chainfile string, genesis string) (*Chain, error) {
  106. chainConfig, err := ioutil.ReadFile(genesis)
  107. if err != nil {
  108. return nil, err
  109. }
  110. var gen core.Genesis
  111. if err := json.Unmarshal(chainConfig, &gen); err != nil {
  112. return nil, err
  113. }
  114. gblock := gen.ToBlock(nil)
  115. // Load chain.rlp.
  116. fh, err := os.Open(chainfile)
  117. if err != nil {
  118. return nil, err
  119. }
  120. defer fh.Close()
  121. var reader io.Reader = fh
  122. if strings.HasSuffix(chainfile, ".gz") {
  123. if reader, err = gzip.NewReader(reader); err != nil {
  124. return nil, err
  125. }
  126. }
  127. stream := rlp.NewStream(reader, 0)
  128. var blocks = make([]*types.Block, 1)
  129. blocks[0] = gblock
  130. for i := 0; ; i++ {
  131. var b types.Block
  132. if err := stream.Decode(&b); err == io.EOF {
  133. break
  134. } else if err != nil {
  135. return nil, fmt.Errorf("at block index %d: %v", i, err)
  136. }
  137. if b.NumberU64() != uint64(i+1) {
  138. return nil, fmt.Errorf("block at index %d has wrong number %d", i, b.NumberU64())
  139. }
  140. blocks = append(blocks, &b)
  141. }
  142. c := &Chain{blocks: blocks, chainConfig: gen.Config}
  143. return c, nil
  144. }