chain.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. package ethtest
  2. import (
  3. "compress/gzip"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "io/ioutil"
  8. "math/big"
  9. "os"
  10. "strings"
  11. "github.com/ethereum/go-ethereum/core"
  12. "github.com/ethereum/go-ethereum/core/forkid"
  13. "github.com/ethereum/go-ethereum/core/types"
  14. "github.com/ethereum/go-ethereum/params"
  15. "github.com/ethereum/go-ethereum/rlp"
  16. )
  17. type Chain struct {
  18. blocks []*types.Block
  19. chainConfig *params.ChainConfig
  20. }
  21. func (c *Chain) WriteTo(writer io.Writer) error {
  22. for _, block := range c.blocks {
  23. if err := rlp.Encode(writer, block); err != nil {
  24. return err
  25. }
  26. }
  27. return nil
  28. }
  29. // Len returns the length of the chain.
  30. func (c *Chain) Len() int {
  31. return len(c.blocks)
  32. }
  33. // TD calculates the total difficulty of the chain.
  34. func (c *Chain) TD(height int) *big.Int { // TODO later on channge scheme so that the height is included in range
  35. sum := big.NewInt(0)
  36. for _, block := range c.blocks[:height] {
  37. sum.Add(sum, block.Difficulty())
  38. }
  39. return sum
  40. }
  41. // ForkID gets the fork id of the chain.
  42. func (c *Chain) ForkID() forkid.ID {
  43. return forkid.NewID(c.chainConfig, c.blocks[0].Hash(), uint64(c.Len()))
  44. }
  45. // Shorten returns a copy chain of a desired height from the imported
  46. func (c *Chain) Shorten(height int) *Chain {
  47. blocks := make([]*types.Block, height)
  48. copy(blocks, c.blocks[:height])
  49. config := *c.chainConfig
  50. return &Chain{
  51. blocks: blocks,
  52. chainConfig: &config,
  53. }
  54. }
  55. // Head returns the chain head.
  56. func (c *Chain) Head() *types.Block {
  57. return c.blocks[c.Len()-1]
  58. }
  59. // loadChain takes the given chain.rlp file, and decodes and returns
  60. // the blocks from the file.
  61. func loadChain(chainfile string, genesis string) (*Chain, error) {
  62. // Open the file handle and potentially unwrap the gzip stream
  63. fh, err := os.Open(chainfile)
  64. if err != nil {
  65. return nil, err
  66. }
  67. defer fh.Close()
  68. var reader io.Reader = fh
  69. if strings.HasSuffix(chainfile, ".gz") {
  70. if reader, err = gzip.NewReader(reader); err != nil {
  71. return nil, err
  72. }
  73. }
  74. stream := rlp.NewStream(reader, 0)
  75. var blocks []*types.Block
  76. for i := 0; ; i++ {
  77. var b types.Block
  78. if err := stream.Decode(&b); err == io.EOF {
  79. break
  80. } else if err != nil {
  81. return nil, fmt.Errorf("at block %d: %v", i, err)
  82. }
  83. blocks = append(blocks, &b)
  84. }
  85. // Open the file handle and potentially unwrap the gzip stream
  86. chainConfig, err := ioutil.ReadFile(genesis)
  87. if err != nil {
  88. return nil, err
  89. }
  90. var gen core.Genesis
  91. if err := json.Unmarshal(chainConfig, &gen); err != nil {
  92. return nil, err
  93. }
  94. return &Chain{
  95. blocks: blocks,
  96. chainConfig: gen.Config,
  97. }, nil
  98. }