github.com/theQRL/go-zond@v0.1.1/zond/api_admin.go (about) 1 // Copyright 2023 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 17 package zond 18 19 import ( 20 "compress/gzip" 21 "errors" 22 "fmt" 23 "io" 24 "os" 25 "strings" 26 27 "github.com/theQRL/go-zond/core" 28 "github.com/theQRL/go-zond/core/types" 29 "github.com/theQRL/go-zond/rlp" 30 ) 31 32 // AdminAPI is the collection of Ethereum full node related APIs for node 33 // administration. 34 type AdminAPI struct { 35 eth *Ethereum 36 } 37 38 // NewAdminAPI creates a new instance of AdminAPI. 39 func NewAdminAPI(eth *Ethereum) *AdminAPI { 40 return &AdminAPI{eth: eth} 41 } 42 43 // ExportChain exports the current blockchain into a local file, 44 // or a range of blocks if first and last are non-nil. 45 func (api *AdminAPI) ExportChain(file string, first *uint64, last *uint64) (bool, error) { 46 if first == nil && last != nil { 47 return false, errors.New("last cannot be specified without first") 48 } 49 if first != nil && last == nil { 50 head := api.eth.BlockChain().CurrentHeader().Number.Uint64() 51 last = &head 52 } 53 if _, err := os.Stat(file); err == nil { 54 // File already exists. Allowing overwrite could be a DoS vector, 55 // since the 'file' may point to arbitrary paths on the drive. 56 return false, errors.New("location would overwrite an existing file") 57 } 58 // Make sure we can create the file to export into 59 out, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) 60 if err != nil { 61 return false, err 62 } 63 defer out.Close() 64 65 var writer io.Writer = out 66 if strings.HasSuffix(file, ".gz") { 67 writer = gzip.NewWriter(writer) 68 defer writer.(*gzip.Writer).Close() 69 } 70 71 // Export the blockchain 72 if first != nil { 73 if err := api.eth.BlockChain().ExportN(writer, *first, *last); err != nil { 74 return false, err 75 } 76 } else if err := api.eth.BlockChain().Export(writer); err != nil { 77 return false, err 78 } 79 return true, nil 80 } 81 82 func hasAllBlocks(chain *core.BlockChain, bs []*types.Block) bool { 83 for _, b := range bs { 84 if !chain.HasBlock(b.Hash(), b.NumberU64()) { 85 return false 86 } 87 } 88 89 return true 90 } 91 92 // ImportChain imports a blockchain from a local file. 93 func (api *AdminAPI) ImportChain(file string) (bool, error) { 94 // Make sure the can access the file to import 95 in, err := os.Open(file) 96 if err != nil { 97 return false, err 98 } 99 defer in.Close() 100 101 var reader io.Reader = in 102 if strings.HasSuffix(file, ".gz") { 103 if reader, err = gzip.NewReader(reader); err != nil { 104 return false, err 105 } 106 } 107 108 // Run actual the import in pre-configured batches 109 stream := rlp.NewStream(reader, 0) 110 111 blocks, index := make([]*types.Block, 0, 2500), 0 112 for batch := 0; ; batch++ { 113 // Load a batch of blocks from the input file 114 for len(blocks) < cap(blocks) { 115 block := new(types.Block) 116 if err := stream.Decode(block); err == io.EOF { 117 break 118 } else if err != nil { 119 return false, fmt.Errorf("block %d: failed to parse: %v", index, err) 120 } 121 // ignore the genesis block when importing blocks 122 if block.NumberU64() == 0 { 123 continue 124 } 125 blocks = append(blocks, block) 126 index++ 127 } 128 if len(blocks) == 0 { 129 break 130 } 131 132 if hasAllBlocks(api.eth.BlockChain(), blocks) { 133 blocks = blocks[:0] 134 continue 135 } 136 // Import the batch and reset the buffer 137 if _, err := api.eth.BlockChain().InsertChain(blocks); err != nil { 138 return false, fmt.Errorf("batch %d: failed to insert: %v", batch, err) 139 } 140 blocks = blocks[:0] 141 } 142 return true, nil 143 }