-
Notifications
You must be signed in to change notification settings - Fork 10
/
http_handlers.go
552 lines (502 loc) · 15.8 KB
/
http_handlers.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
package node
import (
"encoding/hex"
"errors"
"fmt"
"sort"
"strings"
log "github.com/inconshreveable/log15"
ew "github.com/ofgp/ethwatcher"
"github.com/ofgp/ofgp-core/cluster"
"github.com/ofgp/ofgp-core/crypto"
"github.com/ofgp/ofgp-core/distribution"
dgwLog "github.com/ofgp/ofgp-core/log"
"github.com/ofgp/ofgp-core/primitives"
pb "github.com/ofgp/ofgp-core/proto"
)
var apiLog log.Logger
const firstBlockHeight = 0
const defaultCreateUsed = 10
func init() {
apiLog = dgwLog.New("debug", "http_api")
}
func (node *BraftNode) GetNodeTerm() int64 {
return node.blockStore.GetNodeTerm()
}
func (node *BraftNode) GetBlockHeight() int64 {
return node.blockStore.GetCommitHeight()
}
func (node *BraftNode) GetBlockInfo(height int64) *pb.BlockInfo {
blockPack := node.blockStore.GetCommitByHeight(height)
return blockPack.BlockInfo()
}
func (node *BraftNode) GetTxBySidechainTxId(scTxId string) *primitives.TxQueryResult {
return node.txStore.QueryTxInfoBySidechainId(scTxId)
}
// AddWatchedTx 手动添加交易
func (node *BraftNode) AddWatchedTx(tx *pb.WatchedTxInfo) error {
if !node.txStore.HasWatchedTx(tx) {
node.txStore.AddWatchedTx(tx)
} else {
return errors.New("tx already exist")
}
return nil
}
//blcokView for api
type BlockView struct {
Height int64 `json:"height"`
ID string `json:"id"`
PreID string `json:"pre_id"`
TxCnt int `json:"tx_cnt"`
Txs []*TxView `json:"txs"`
Time int64 `json:"time"` //unix 时间戳
Size int `json:"size"` //块大小
CreatedUsed int64 `json:"created_used"` //块被创建花费的时间
Miner string `json:"miner"` //产生块的服务器
}
type TxView struct {
FromTxHash string `json:"from_tx_hash"` //转出txhash
ToTxHash string `json:"to_tx_hash"` //转入txhash
DGWTxHash string `json:"dgw_hash"` //dgwtxhash
From string `json:"from"` //转出链
To string `json:"to"` //转入链
Time int64 `json:"time"`
Block string `json:"block"` //所在区块blockID
BlockHeight int64 `json:"block_height"` //所在区块高度
Amount int64 `json:"amount"`
ToAddrs []string `json:"to_addrs"`
FromFee int64 `json:"from_fee"`
DGWFee int64 `json:"dgw_fee"`
ToFee int64 `json:"to_fee"`
TokenCode uint32 `json:"token_code"`
AppCode uint32 `json:"app_code"`
FinalAmount int64 `json:"final_amount"` //扣除手续费后的金额
}
func getHexString(digest *crypto.Digest256) string {
if digest == nil || len(digest.Data) == 0 {
return ""
}
return hex.EncodeToString(digest.Data)
}
func (node *BraftNode) createTxView(blockID string, height int64, tx *pb.Transaction) *TxView {
if tx == nil {
apiLog.Error(fmt.Sprintf("block:%s transaciton is nil", blockID))
return nil
}
watchedTx := tx.GetWatchedTx()
if watchedTx == nil {
apiLog.Error(fmt.Sprintf("block:%s has no watched tx", blockID))
return nil
}
addrList := watchedTx.GetRechargeList()
addrs := make([]string, 0)
for _, addr := range addrList {
addrs = append(addrs, addr.Address)
}
var tokenCode, appCode uint32
if watchedTx.From == "eth" || watchedTx.From == "xin" { //熔币
tokenCode, appCode = watchedTx.TokenTo, watchedTx.TokenFrom
} else { //铸币
tokenCode, appCode = watchedTx.TokenFrom, watchedTx.TokenTo
}
txView := &TxView{
FromTxHash: watchedTx.GetTxid(),
DGWTxHash: getHexString(tx.GetId()),
ToTxHash: tx.NewlyTxId,
From: watchedTx.From,
To: watchedTx.To,
Block: blockID,
BlockHeight: height,
Amount: watchedTx.Amount,
FromFee: watchedTx.GetFee(),
ToAddrs: addrs,
Time: tx.Time,
TokenCode: tokenCode,
AppCode: appCode,
FinalAmount: tx.Amount,
DGWFee: watchedTx.Amount - tx.Amount,
}
return txView
}
func (node *BraftNode) createBlockView(createdUsed int64, blockPack *pb.BlockPack) *BlockView {
block := blockPack.Block()
var txViews []*TxView
if block == nil {
return nil
}
var height int64
var nodeID int32
height = blockPack.Height()
if blockPack.GetInit() != nil {
nodeID = blockPack.GetInit().GetNodeId()
}
peerNode := node.peerManager.GetNode(nodeID)
var miner string
if peerNode != nil {
miner = peerNode.Name
}
txs := block.Txs
txViews = make([]*TxView, 0)
blockID := getHexString(block.GetId())
for _, tx := range txs {
txView := node.createTxView(blockID, height, tx)
if txView != nil {
txViews = append(txViews, txView)
} else {
apiLog.Error("create txview err", "transaction", tx)
}
}
bw := &BlockView{
Height: height,
ID: getHexString(block.Id),
PreID: getHexString(block.PrevBlockId),
TxCnt: len(txViews),
Txs: txViews,
Time: int64(block.TimestampMs / 1000),
Size: blockPack.XXX_Size(),
CreatedUsed: createdUsed,
Miner: miner,
}
return bw
}
//获取最新区块
func (node *BraftNode) GetBlockCurrent() *BlockView {
curHeight := node.blockStore.GetCommitHeight()
return node.GetBlockBytHeight(curHeight)
}
//获取区块 start 开始高度 end结束高度[start,end)
func (node *BraftNode) GetBlocks(start, end int64) []*BlockView {
if end <= start {
apiLog.Error(fmt.Sprintf("end:%d is less than start:%d", start, end))
return nil
}
var beiginFromFirstBlock bool
if start < firstBlockHeight {
apiLog.Error("start < firstBlockHeight")
return nil
}
if start == firstBlockHeight {
beiginFromFirstBlock = true
}
if start > firstBlockHeight { //大于创世块
start = start - 1
}
blockPacks := node.blockStore.GetCommitsByHeightSec(start, end)
size := len(blockPacks)
if size == 0 {
return nil
}
blcokViews := make([]*BlockView, 0)
if beiginFromFirstBlock { //==创世块
blockView := node.createBlockView(0, blockPacks[0])
blcokViews = append(blcokViews, blockView)
}
pre := blockPacks[0]
for i := 1; i < size; i++ {
blcokPack := blockPacks[i]
if blcokPack == nil {
continue
}
var createdUsed int64
if pre.TimestampMs() == 0 {
createdUsed = defaultCreateUsed
} else {
createdUsed = blcokPack.TimestampMs()/1000 - pre.TimestampMs()/1000
}
blockView := node.createBlockView(createdUsed, blcokPack)
blcokViews = append(blcokViews, blockView)
pre = blcokPack
}
return blcokViews
}
//根据高度获取block
func (node *BraftNode) GetBlockBytHeight(height int64) *BlockView {
views := node.GetBlocks(height, height+1)
if len(views) == 0 {
return nil
}
return views[0]
}
func (node *BraftNode) GetBlockByID(id string) (*BlockView, error) {
idreal, err := hex.DecodeString(id)
if err != nil {
return nil, err
}
block := node.blockStore.GetBlockByID(idreal)
var preBlock *pb.BlockPack
if block.PrevBlockId() != nil && len(block.PrevBlockId().Data) > 0 {
preBlock = node.blockStore.GetBlockByID(block.PrevBlockId().Data)
}
var createdUsed int64
if preBlock != nil {
createdUsed = block.TimestampMs()/1000 - preBlock.TimestampMs()/1000
}
blockView := node.createBlockView(createdUsed, block)
return blockView, nil
}
//根据tx_id查询 transaction 不同链的tx_id用相同的pre存储
func (node *BraftNode) GetTransacitonByTxID(txID string) *TxView {
txQueryResult := node.txStore.GetTx(txID)
if txQueryResult == nil {
return nil
}
tx := txQueryResult.Tx
blockID := getHexString(txQueryResult.BlockID)
txView := node.createTxView(blockID, txQueryResult.Height, tx)
return txView
}
// FakeCommitBlock 人工写区块,仅做测试用
func (node *BraftNode) FakeCommitBlock(blockPack *pb.BlockPack) {
node.blockStore.JustCommitIt(blockPack)
node.txStore.OnNewBlockCommitted(blockPack)
}
//节点数据
type NodeView struct {
id int
IP string `json:"ip"`
HostName string `json:"host_name"`
IsLeader bool `json:"is_leader"`
IsOnline bool `json:"is_online"`
FiredCnt int32 `json:"fired_cnt"` //被替换掉leader的次数
EthHeight int64 `json:"eth_height"`
BchHeight int64 `json:"bch_height"`
BtcHeight int64 `json:"btc_height"`
}
func (node *BraftNode) GetNodes() []NodeView {
nodeViews := make([]NodeView, 0)
term := node.GetNodeTerm()
leaderID := cluster.LeaderNodeOfTerm(term)
apiLog.Error("leader id is", "leaderID", leaderID, "term is ", term)
nodeRuntimeInfos := node.peerManager.GetNodeRuntimeInfos()
for _, node := range cluster.NodeList {
var isLeader bool
ip, _ := getHostAndPort(node.Url)
if leaderID == node.Id {
isLeader = true
}
var firedCnt int32
ethH, btcH, bchH, LeaderCnt := getHeightAndLeaderCnt(node.Id, nodeRuntimeInfos)
if isLeader && LeaderCnt > 0 {
firedCnt = LeaderCnt - 1
} else {
firedCnt = LeaderCnt
}
nodeView := NodeView{
IP: ip,
HostName: node.Name,
IsLeader: isLeader,
IsOnline: node.IsNormal,
EthHeight: ethH,
BtcHeight: btcH,
BchHeight: bchH,
FiredCnt: firedCnt,
}
nodeViews = append(nodeViews, nodeView)
}
sort.Slice(nodeViews, func(i, j int) bool {
return nodeViews[i].id < nodeViews[j].id
})
return nodeViews
}
type ChainRegInfo struct {
NewChain string `json:"new_chain"`
TargetChain string `json:"target_chain"`
}
type ChainRegID struct {
ChainID uint32 `json:"chain_id"`
}
type TokenRegInfo struct {
ContractAddr string `json:"contract_addr"`
Chain string `json:"chain"`
ReceptChain uint32 `json:"recept_chain"`
ReceptToken uint32 `json:"recept_token"`
}
type TokenRegID struct {
TokenID uint32 `json:"token_id"`
}
// ChainRegister 新链注册
func (node *BraftNode) ChainRegister(regInfo *ChainRegInfo) {
if regInfo.TargetChain == "eth" {
proposal := strings.Join([]string{"CR", regInfo.TargetChain, regInfo.NewChain}, "_")
_, err := node.ethWatcher.GatewayTransaction(node.signer.PubKeyHex, node.signer.PubkeyHash,
ew.VOTE_METHOD_ADDCHAIN, regInfo.NewChain, proposal)
if err != nil {
nodeLogger.Error("register new chain failed", "err", err, "newchain", regInfo.NewChain)
} else {
nodeLogger.Debug("register new chain success", "newchain", regInfo.NewChain)
}
}
}
// GetChainRegisterID 查询链注册结果,如果成功,返回chainID,否则返回0
func (node *BraftNode) GetChainRegisterID(newChain string, targetChain string) *ChainRegID {
if targetChain == "eth" {
chainID := node.ethWatcher.GetChainCode(newChain)
return &ChainRegID{ChainID: chainID}
}
return nil
}
// TokenRegister 新token合约注册
func (node *BraftNode) TokenRegister(regInfo *TokenRegInfo) {
if regInfo.Chain == "eth" {
// 调用ETH合约接口注册新的token合约, proposal就使用contractaddr
addr := ew.HexToAddress(regInfo.ContractAddr)
_, err := node.ethWatcher.GatewayTransaction(node.signer.PubKeyHex, node.signer.PubkeyHash, ew.VOTE_METHOD_ADDAPP,
addr, regInfo.ReceptChain, regInfo.ReceptToken, "TR_"+regInfo.ContractAddr)
if err != nil {
nodeLogger.Error("register new token failed", "err", err, "contractaddr", regInfo.ContractAddr)
} else {
nodeLogger.Debug("register new token success", "contractaddr", regInfo.ContractAddr)
}
}
}
// GetTokenRegisterID 查询token注册结果,如果成功,则返回tokenID, 否则返回0
func (node *BraftNode) GetTokenRegisterID(chain string, contractAddr string) *TokenRegID {
if chain == "eth" {
tokenID := node.ethWatcher.GetAppCode(contractAddr)
return &TokenRegID{TokenID: tokenID}
}
return nil
}
// ManualMintRequest 手工铸币结构
type ManualMintRequest struct {
Amount int64 `json:"amount"`
Address string `json:"address"`
Proposal string `json:"proposal"`
Chain uint32 `json:"chain"`
Token uint32 `json:"token"`
}
// ManualMint 手工铸币
func (node *BraftNode) ManualMint(mintInfo *ManualMintRequest) {
addr := ew.HexToAddress(mintInfo.Address)
_, err := node.ethWatcher.GatewayTransaction(node.signer.PubKeyHex, node.signer.PubkeyHash, ew.VOTE_METHOD_MINT,
mintInfo.Token, uint64(mintInfo.Amount), addr, "MM_"+mintInfo.Proposal)
if err != nil {
nodeLogger.Error("manual mint failed", "err", err)
} else {
nodeLogger.Debug("manual mint success")
}
}
func getHostAndPort(url string) (host, port string) {
if url == "" {
return
}
strs := strings.Split(url, ":")
if len(strs) >= 2 {
host = strs[0]
port = strs[1]
}
return
}
func getHeightAndLeaderCnt(nodeID int32,
apiDatas map[int32]*pb.NodeRuntimeInfo) (ethHeight, btcHeight, bchHeight int64, leaderCnt int32) {
apiData := apiDatas[nodeID]
if apiData == nil {
return
}
return apiData.EthHeight, apiData.BtcHeight, apiData.BchHeight, apiData.LeaderCnt
}
// GetMinBCHMintAmount 返回BCH链铸币的最小金额
func (node *BraftNode) GetMinBCHMintAmount() int64 {
return node.minBCHMintAmount
}
// GetMinBTCMintAmount 返回BCH链铸币的最小金额
func (node *BraftNode) GetMinBTCMintAmount() int64 {
return node.minBTCMintAmount
}
// GetMinBurnAmount 返回熔币的最小金额
func (node *BraftNode) GetMinBurnAmount() int64 {
return node.minBurnAmount
}
// GetMintFeeRate 返回铸币的手续费
func (node *BraftNode) GetMintFeeRate() int64 {
return node.mintFeeRate
}
// GetBurnFeeRate 返回熔币的手续费
func (node *BraftNode) GetBurnFeeRate() int64 {
return node.burnFeeRate
}
// AddProposal 新增一个分配提案
func (node *BraftNode) AddProposal(p *distribution.Proposal) bool {
return node.proposalManager.AddProposal(p)
}
// GetProposal 获取指定的提案
func (node *BraftNode) GetProposal(proposalID string) *distribution.DistributionInfo {
return node.proposalManager.GetProposal(proposalID)
}
// GetAllProposal 获取所有的提案
func (node *BraftNode) GetAllProposal() []*distribution.DistributionInfo {
return node.proposalManager.ListProposal()
}
// DeleteProposal 删除指定的提案,注意只有处于new或者执行失败的情况下,提案才会被删除
func (node *BraftNode) DeleteProposal(proposalID string) bool {
return node.proposalManager.DeleteProposal(proposalID)
}
// ExecuteProposal 执行指定的提案
func (node *BraftNode) ExecuteProposal(proposalID string) {
node.proposalManager.ExecuteProposal(proposalID)
}
// AddSideTx 添加侧链tx
func (node *BraftNode) AddSideTx(txID string, chain string) error {
var watchedTx *pb.WatchedTxInfo
switch chain {
case "bch":
subTx := node.bchWatcher.GetTxByHash(txID)
if subTx != nil {
if subTx.SubTx != nil {
watchedTx = pb.BtcToPbTx(subTx.SubTx)
} else {
return errors.New("bch sub tx nil")
}
} else {
return errors.New("get bch tx nil")
}
case "btc":
subTx := node.btcWatcher.GetTxByHash(txID)
if subTx != nil {
if subTx.SubTx != nil {
watchedTx = pb.BtcToPbTx(subTx.SubTx)
} else {
return errors.New("btc sub tx nil")
}
} else {
return errors.New("get btc tx nil")
}
case "eth":
fmt.Printf("add watchedtx txid:%s\n", txID)
event, err := node.ethWatcher.GetEventByHash(txID)
if err == nil {
if ew.TOKEN_METHOD_BURN == event.Method {
if (event.Events & ew.TX_STATUS_FAILED) != 0 {
nodeLogger.Debug("burn tx is failed in contract")
return errors.New("burn tx is failed in contract")
}
burnData := event.ExtraData.(*ew.ExtraBurnData)
nodeLogger.Debug("receive eth burn", "tx", burnData.ScTxid)
if burnData.Amount < uint64(node.minBurnAmount) {
nodeLogger.Debug("amount is less than minimal amount", "sctxid", burnData.ScTxid)
return errors.New("amount is less than minimal amount")
}
watchedTx = pb.EthToPbTx(burnData)
}
} else {
return errors.New("get eth tx nil")
}
case "xin":
event, err := node.xinWatcher.GetEventByTxid(txID)
// nodeLogger.Debug("get xin event", "account", event.Account, "name", event.Name, "memo", event.Memo, "amount", event.Amount, "block", event.BlockNum, "index", event.Index)
if err != nil {
nodeLogger.Error("get xin err", "err", err, "scTxID", txID)
return err
}
if event != nil {
watchedTx = pb.XINToPbTx(event)
if watchedTx == nil {
return errors.New("xin event to watched err")
}
} else {
return errors.New("get xin tx nil")
}
}
err := node.txStore.AddWatchedInfo(watchedTx)
return err
}