github.com/koko1123/flow-go-1@v0.29.6/utils/debug/remoteView.go (about) 1 package debug 2 3 import ( 4 "context" 5 "fmt" 6 7 "google.golang.org/grpc" 8 9 "github.com/onflow/flow/protobuf/go/flow/execution" 10 11 "github.com/koko1123/flow-go-1/fvm/state" 12 "github.com/koko1123/flow-go-1/model/flow" 13 ) 14 15 // RemoteView provides a view connected to a live execution node to read the registers 16 // writen values are kept inside a map 17 // 18 // TODO implement register touches 19 type RemoteView struct { 20 Parent *RemoteView 21 Delta map[string]flow.RegisterValue 22 Cache registerCache 23 BlockID []byte 24 BlockHeader *flow.Header 25 connection *grpc.ClientConn 26 executionAPIclient execution.ExecutionAPIClient 27 } 28 29 // A RemoteViewOption sets a configuration parameter for the remote view 30 type RemoteViewOption func(view *RemoteView) *RemoteView 31 32 // WithFileCache sets the output path to store 33 // register values so can be fetched from a file cache 34 // it loads the values from the cache upon object construction 35 func WithCache(cache registerCache) RemoteViewOption { 36 return func(view *RemoteView) *RemoteView { 37 view.Cache = cache 38 return view 39 } 40 } 41 42 // WithBlockID sets the blockID for the remote view, if not used 43 // remote view will use the latest sealed block 44 func WithBlockID(blockID flow.Identifier) RemoteViewOption { 45 return func(view *RemoteView) *RemoteView { 46 view.BlockID = blockID[:] 47 var err error 48 view.BlockHeader, err = view.getBlockHeader(blockID) 49 if err != nil { 50 panic(err) 51 } 52 return view 53 } 54 } 55 56 func NewRemoteView(grpcAddress string, opts ...RemoteViewOption) *RemoteView { 57 conn, err := grpc.Dial(grpcAddress, grpc.WithInsecure()) //nolint:staticcheck 58 if err != nil { 59 panic(err) 60 } 61 62 view := &RemoteView{ 63 connection: conn, 64 executionAPIclient: execution.NewExecutionAPIClient(conn), 65 Delta: make(map[string]flow.RegisterValue), 66 Cache: newMemRegisterCache(), 67 } 68 69 view.BlockID, view.BlockHeader, err = view.getLatestBlockID() 70 if err != nil { 71 panic(err) 72 } 73 74 for _, applyOption := range opts { 75 view = applyOption(view) 76 } 77 return view 78 } 79 80 func (v *RemoteView) Done() { 81 v.connection.Close() 82 } 83 84 func (v *RemoteView) getLatestBlockID() ([]byte, *flow.Header, error) { 85 req := &execution.GetLatestBlockHeaderRequest{ 86 IsSealed: true, 87 } 88 89 resp, err := v.executionAPIclient.GetLatestBlockHeader(context.Background(), req) 90 if err != nil { 91 return nil, nil, err 92 } 93 94 // TODO set chainID and parentID 95 header := &flow.Header{ 96 Height: resp.Block.Height, 97 Timestamp: resp.Block.Timestamp.AsTime(), 98 } 99 100 return resp.Block.Id, header, nil 101 } 102 103 func (v *RemoteView) getBlockHeader(blockID flow.Identifier) (*flow.Header, error) { 104 req := &execution.GetBlockHeaderByIDRequest{ 105 Id: blockID[:], 106 } 107 108 resp, err := v.executionAPIclient.GetBlockHeaderByID(context.Background(), req) 109 if err != nil { 110 return nil, err 111 } 112 113 // TODO set chainID and parentID 114 header := &flow.Header{ 115 Height: resp.Block.Height, 116 Timestamp: resp.Block.Timestamp.AsTime(), 117 } 118 119 return header, nil 120 } 121 122 func (v *RemoteView) NewChild() state.View { 123 return &RemoteView{ 124 Parent: v, 125 executionAPIclient: v.executionAPIclient, 126 connection: v.connection, 127 Cache: newMemRegisterCache(), 128 Delta: make(map[string][]byte), 129 } 130 } 131 132 func (v *RemoteView) MergeView(o state.View) error { 133 var other *RemoteView 134 var ok bool 135 if other, ok = o.(*RemoteView); !ok { 136 return fmt.Errorf("can not merge: view type mismatch (given: %T, expected:RemoteView)", o) 137 } 138 139 for k, value := range other.Delta { 140 v.Delta[k] = value 141 } 142 return nil 143 } 144 145 func (v *RemoteView) DropDelta() { 146 v.Delta = make(map[string]flow.RegisterValue) 147 } 148 149 func (v *RemoteView) Set(owner, key string, value flow.RegisterValue) error { 150 v.Delta[owner+"~"+key] = value 151 return nil 152 } 153 154 func (v *RemoteView) Get(owner, key string) (flow.RegisterValue, error) { 155 156 // first check the delta 157 value, found := v.Delta[owner+"~"+key] 158 if found { 159 return value, nil 160 } 161 162 // then check the read cache 163 value, found = v.Cache.Get(owner, key) 164 if found { 165 return value, nil 166 } 167 168 // then call the parent (if exist) 169 if v.Parent != nil { 170 return v.Parent.Get(owner, key) 171 } 172 173 // last use the grpc api the 174 req := &execution.GetRegisterAtBlockIDRequest{ 175 BlockId: []byte(v.BlockID), 176 RegisterOwner: []byte(owner), 177 RegisterKey: []byte(key), 178 } 179 180 // TODO use a proper context for timeouts 181 resp, err := v.executionAPIclient.GetRegisterAtBlockID(context.Background(), req) 182 if err != nil { 183 return nil, err 184 } 185 186 v.Cache.Set(owner, key, resp.Value) 187 188 // append value to the file cache 189 190 return resp.Value, nil 191 } 192 193 // returns all the registers that has been touched 194 func (v *RemoteView) AllRegisters() []flow.RegisterID { 195 panic("Not implemented yet") 196 } 197 198 func (v *RemoteView) RegisterUpdates() ([]flow.RegisterID, []flow.RegisterValue) { 199 panic("Not implemented yet") 200 } 201 202 func (v *RemoteView) Touch(owner, key string) error { 203 // no-op for now 204 return nil 205 } 206 207 func (v *RemoteView) Delete(owner, key string) error { 208 v.Delta[owner+"~"+key] = nil 209 return nil 210 }