github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/utils/debug/remoteView.go (about) 1 package debug 2 3 import ( 4 "context" 5 6 "github.com/onflow/flow/protobuf/go/flow/execution" 7 "google.golang.org/grpc" 8 "google.golang.org/grpc/credentials/insecure" 9 10 "github.com/onflow/flow-go/model/flow" 11 ) 12 13 // RemoteStorageSnapshot provides a storage snapshot connected to a live 14 // execution node to read the registers. 15 type RemoteStorageSnapshot struct { 16 Cache registerCache 17 BlockID []byte 18 BlockHeader *flow.Header 19 connection *grpc.ClientConn 20 executionAPIclient execution.ExecutionAPIClient 21 } 22 23 // A RemoteStorageSnapshotOption sets a configuration parameter for the remote 24 // snapshot 25 type RemoteStorageSnapshotOption func(*RemoteStorageSnapshot) *RemoteStorageSnapshot 26 27 // WithFileCache sets the output path to store 28 // register values so can be fetched from a file cache 29 // it loads the values from the cache upon object construction 30 func WithCache(cache registerCache) RemoteStorageSnapshotOption { 31 return func(snapshot *RemoteStorageSnapshot) *RemoteStorageSnapshot { 32 snapshot.Cache = cache 33 return snapshot 34 } 35 } 36 37 // WithBlockID sets the blockID for the remote snapshot, if not used 38 // remote snapshot will use the latest sealed block 39 func WithBlockID(blockID flow.Identifier) RemoteStorageSnapshotOption { 40 return func(snapshot *RemoteStorageSnapshot) *RemoteStorageSnapshot { 41 snapshot.BlockID = blockID[:] 42 var err error 43 snapshot.BlockHeader, err = snapshot.getBlockHeader(blockID) 44 if err != nil { 45 panic(err) 46 } 47 return snapshot 48 } 49 } 50 51 func NewRemoteStorageSnapshot( 52 grpcAddress string, 53 opts ...RemoteStorageSnapshotOption, 54 ) *RemoteStorageSnapshot { 55 conn, err := grpc.Dial( 56 grpcAddress, 57 grpc.WithTransportCredentials(insecure.NewCredentials())) 58 if err != nil { 59 panic(err) 60 } 61 62 snapshot := &RemoteStorageSnapshot{ 63 connection: conn, 64 executionAPIclient: execution.NewExecutionAPIClient(conn), 65 Cache: newMemRegisterCache(), 66 } 67 68 snapshot.BlockID, snapshot.BlockHeader, err = snapshot.getLatestBlockID() 69 if err != nil { 70 panic(err) 71 } 72 73 for _, applyOption := range opts { 74 snapshot = applyOption(snapshot) 75 } 76 return snapshot 77 } 78 79 func (snapshot *RemoteStorageSnapshot) Close() error { 80 return snapshot.connection.Close() 81 } 82 83 func (snapshot *RemoteStorageSnapshot) getLatestBlockID() ( 84 []byte, 85 *flow.Header, 86 error, 87 ) { 88 req := &execution.GetLatestBlockHeaderRequest{ 89 IsSealed: true, 90 } 91 92 resp, err := snapshot.executionAPIclient.GetLatestBlockHeader( 93 context.Background(), 94 req) 95 if err != nil { 96 return nil, nil, err 97 } 98 99 // TODO set chainID and parentID 100 header := &flow.Header{ 101 Height: resp.Block.Height, 102 Timestamp: resp.Block.Timestamp.AsTime(), 103 } 104 105 return resp.Block.Id, header, nil 106 } 107 108 func (snapshot *RemoteStorageSnapshot) getBlockHeader( 109 blockID flow.Identifier, 110 ) ( 111 *flow.Header, 112 error, 113 ) { 114 req := &execution.GetBlockHeaderByIDRequest{ 115 Id: blockID[:], 116 } 117 118 resp, err := snapshot.executionAPIclient.GetBlockHeaderByID( 119 context.Background(), 120 req) 121 if err != nil { 122 return nil, err 123 } 124 125 // TODO set chainID and parentID 126 header := &flow.Header{ 127 Height: resp.Block.Height, 128 Timestamp: resp.Block.Timestamp.AsTime(), 129 } 130 131 return header, nil 132 } 133 134 func (snapshot *RemoteStorageSnapshot) Get( 135 id flow.RegisterID, 136 ) ( 137 flow.RegisterValue, 138 error, 139 ) { 140 // then check the read cache 141 value, found := snapshot.Cache.Get(id.Owner, id.Key) 142 if found { 143 return value, nil 144 } 145 146 // last use the grpc api the 147 req := &execution.GetRegisterAtBlockIDRequest{ 148 BlockId: []byte(snapshot.BlockID), 149 RegisterOwner: []byte(id.Owner), 150 RegisterKey: []byte(id.Key), 151 } 152 153 // TODO use a proper context for timeouts 154 resp, err := snapshot.executionAPIclient.GetRegisterAtBlockID( 155 context.Background(), 156 req) 157 if err != nil { 158 return nil, err 159 } 160 161 snapshot.Cache.Set(id.Owner, id.Key, resp.Value) 162 163 // append value to the file cache 164 165 return resp.Value, nil 166 }