This repository has been archived by the owner on Nov 23, 2022. It is now read-only.
/
public_baker.go
152 lines (122 loc) · 3.98 KB
/
public_baker.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
package public_baker
import (
"context"
script "blockwatch.cc/tzgo/micheline"
"github.com/everstake/teztracker/models"
"github.com/everstake/teztracker/repos/baker"
"github.com/everstake/teztracker/repos/operation"
"github.com/everstake/teztracker/services/michelson"
"github.com/everstake/teztracker/services/rpc_client"
)
type BakesProvider interface {
Operation(ctx context.Context, blockHash, transactionHash string) (op rpc_client.Operation, err error)
Script(ctx context.Context, contractHash string) (bm michelson.BigMap, err error)
}
type UnitOfWork interface {
GetBaker() baker.Repo
GetOperation() operation.Repo
}
const (
BakerRegistryContract = "KT1ChNsEFxwyCbJyWGSL3KdjeXE28AY1Kaog"
operationKindTransaction = "transaction"
)
func MonitorPublicBakers(ctx context.Context, unit UnitOfWork, rpc BakesProvider) (err error) {
bakerRepo := unit.GetBaker()
publicBakers, err := bakerRepo.BakerRegistryList()
if err != nil {
return err
}
operationRepo := unit.GetOperation()
operations, err := operationRepo.List(nil, []string{operationKindTransaction}, nil, []string{BakerRegistryContract}, 100, 0, 0, nil)
if err != nil {
return err
}
operationsByBaker := map[string]models.Operation{}
//Group operations by source
for key := range operations {
if elem, ok := operationsByBaker[operations[key].Source]; ok {
if elem.Level < operationsByBaker[operations[key].Source].Level {
elem = operationsByBaker[operations[key].Source]
}
continue
}
operationsByBaker[operations[key].Source] = operations[key]
}
bakersMap := map[string]models.BakerRegistry{}
//Group bakers by pkh
for key := range publicBakers {
bakersMap[publicBakers[key].Delegate] = publicBakers[key]
}
contractContainer, err := InitContractScript(ctx, rpc, BakerRegistryContract)
if err != nil {
return err
}
for key, value := range operationsByBaker {
//Baker have actual data
if value.OperationID.Int64 <= bakersMap[key].LastUpdateId {
continue
}
publicBaker, isStorageOperation, err := GetPublicBakerInfo(ctx, rpc, contractContainer, value.BlockHash.String, value.OperationGroupHash.String)
if err != nil {
return err
}
//Not process storage operations
if isStorageOperation {
continue
}
publicBaker.LastUpdateId = value.OperationID.Int64
err = bakerRepo.SavePublicBaker(publicBaker)
if err != nil {
return err
}
}
return nil
}
func InitContractScript(ctx context.Context, rpc BakesProvider, contractHash string) (container michelson.BigMapContainer, err error) {
contractScript, err := rpc.Script(ctx, contractHash)
if err != nil {
return container, err
}
container = michelson.NewBigMapContainer()
//Insert params locate on L branch
//R branch contains params for storage
container.InitPath(contractScript.Code.Args[0].Args[0])
return container, nil
}
func GetPublicBakerInfo(ctx context.Context, rpc BakesProvider, container michelson.BigMapContainer, blockHash, operationHash string) (publicBaker models.BakerRegistry, isStorageOperation bool, err error) {
op, err := rpc.Operation(ctx, blockHash, operationHash)
if err != nil {
return publicBaker, false, err
}
//Find required operation
var index int
for i := range op.Contents {
if op.Contents[i].Kind != operationKindTransaction {
continue
}
index = i
}
v := op.Contents[index].Parameters.Value
//Check unusual operations
if op.Contents[index].Parameters.Value.OpCode != script.D_LEFT {
//Not process updates of internal contract storage
if op.Contents[index].Parameters.Value.OpCode == script.D_RIGHT {
return publicBaker, true, nil
}
//For txs where missed highest level of tree
v = script.Prim{
OpCode: script.D_LEFT,
Args: []script.Prim{op.Contents[index].Parameters.Value},
}
}
container.ParseValues(op.Contents[index].Parameters.Entrypoint, v)
bt, err := container.MarshalJSON()
if err != nil {
return publicBaker, false, err
}
err = publicBaker.Unmarshal(bt)
if err != nil {
return publicBaker, false, err
}
return publicBaker, false, nil
}