-
Notifications
You must be signed in to change notification settings - Fork 10
/
api_admin.go
136 lines (119 loc) · 4.06 KB
/
api_admin.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright 2018 The cpchain authors
// This file is part of the cpchain library.
//
// The cpchain library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The cpchain library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the cpchain library. If not, see <http://www.gnu.org/licenses/>.
package cpc
import (
"compress/gzip"
"fmt"
"io"
"os"
"strings"
"bitbucket.org/cpchain/chain/api/grpc/v1/admin"
"bitbucket.org/cpchain/chain/api/grpc/v1/common"
"bitbucket.org/cpchain/chain/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"golang.org/x/net/context"
"google.golang.org/grpc"
)
// ChainManager is the collection of Ethereum full node-related APIs
// exposed over the private admin endpoint.
type ChainManager struct {
c *CpchainService
}
// NewAdminManager creates a new API definition for the full node private
// admin methods of the Ethereum service.
func NewAdminManager(c *CpchainService) *ChainManager {
return &ChainManager{c: c}
}
// IsPublic if public default
func (c *ChainManager) IsPublic() bool {
return false
}
// Namespace namespace
func (c *ChainManager) Namespace() string {
return "admin"
}
// RegisterServer register GAPI to grpc
func (c *ChainManager) RegisterServer(s *grpc.Server) {
admin.RegisterAdminManagerServer(s, c)
}
// RegisterJsonRpc register GAPI to restfull json
func (c *ChainManager) RegisterJsonRpc(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) {
admin.RegisterAdminManagerHandlerFromEndpoint(ctx, mux, endpoint, opts)
}
// ExportChain exports the current blockchain into a local file.
func (api *ChainManager) ExportChain(ctx context.Context, file *admin.File) (*common.IsOk, error) {
// Make sure we can create the file to export into
out, err := os.OpenFile(file.File, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
if err != nil {
return &common.IsOk{IsOk: false}, err
}
defer out.Close()
var writer io.Writer = out
if strings.HasSuffix(file.File, ".gz") {
writer = gzip.NewWriter(writer)
defer writer.(*gzip.Writer).Close()
}
// Export the blockchain
if err := api.c.BlockChain().Export(writer); err != nil {
return &common.IsOk{IsOk: false}, err
}
return &common.IsOk{IsOk: true}, nil
}
// ImportChain imports a blockchain from a local file.
func (api *ChainManager) ImportChain(ctx context.Context, file *admin.File) (*common.IsOk, error) {
// Make sure the can access the file to import
in, err := os.Open(file.File)
if err != nil {
return &common.IsOk{IsOk: false}, err
}
defer in.Close()
var reader io.Reader = in
if strings.HasSuffix(file.File, ".gz") {
if reader, err = gzip.NewReader(reader); err != nil {
return &common.IsOk{IsOk: false}, err
}
}
// Run actual the import in pre-configured batches
stream := rlp.NewStream(reader, 0)
blocks, index := make([]*types.Block, 0, 2500), 0
for batch := 0; ; batch++ {
// Load a batch of blocks from the input file
for len(blocks) < cap(blocks) {
block := new(types.Block)
if err := stream.Decode(block); err == io.EOF {
break
} else if err != nil {
return &common.IsOk{IsOk: false}, fmt.Errorf("block %d: failed to parse: %v", index, err)
}
blocks = append(blocks, block)
index++
}
if len(blocks) == 0 {
break
}
if hasAllBlocks(api.c.BlockChain(), blocks) {
blocks = blocks[:0]
continue
}
// Import the batch and reset the buffer
if _, err := api.c.BlockChain().InsertChain(blocks); err != nil {
return &common.IsOk{IsOk: false}, fmt.Errorf("batch %d: failed to insert: %v", batch, err)
}
blocks = blocks[:0]
}
return &common.IsOk{IsOk: true}, nil
}