github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/rpc/rpcquery/query_server.go (about) 1 package rpcquery 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 8 "github.com/hyperledger/burrow/acm" 9 "github.com/hyperledger/burrow/acm/acmstate" 10 "github.com/hyperledger/burrow/acm/validator" 11 "github.com/hyperledger/burrow/bcm" 12 "github.com/hyperledger/burrow/consensus/tendermint" 13 "github.com/hyperledger/burrow/crypto" 14 "github.com/hyperledger/burrow/deploy/compile" 15 "github.com/hyperledger/burrow/event/query" 16 "github.com/hyperledger/burrow/execution/names" 17 "github.com/hyperledger/burrow/execution/proposal" 18 "github.com/hyperledger/burrow/execution/registry" 19 "github.com/hyperledger/burrow/execution/state" 20 "github.com/hyperledger/burrow/logging" 21 "github.com/hyperledger/burrow/rpc" 22 "github.com/hyperledger/burrow/txs/payload" 23 tmproto "github.com/tendermint/tendermint/proto/tendermint/types" 24 tmtypes "github.com/tendermint/tendermint/types" 25 "google.golang.org/grpc/codes" 26 "google.golang.org/grpc/status" 27 ) 28 29 type queryServer struct { 30 UnimplementedQueryServer 31 state QueryState 32 blockchain bcm.BlockchainInfo 33 nodeView *tendermint.NodeView 34 logger *logging.Logger 35 } 36 37 var _ QueryServer = &queryServer{} 38 39 type QueryState interface { 40 acmstate.IterableStatsReader 41 acmstate.MetadataReader 42 names.IterableReader 43 registry.IterableReader 44 proposal.IterableReader 45 validator.History 46 } 47 48 func NewQueryServer(state QueryState, blockchain bcm.BlockchainInfo, nodeView *tendermint.NodeView, logger *logging.Logger) *queryServer { 49 return &queryServer{ 50 state: state, 51 blockchain: blockchain, 52 nodeView: nodeView, 53 logger: logger, 54 } 55 } 56 57 func (qs *queryServer) Status(ctx context.Context, param *StatusParam) (*rpc.ResultStatus, error) { 58 return rpc.Status(qs.blockchain, qs.state, qs.nodeView, param.BlockTimeWithin, param.BlockSeenTimeWithin) 59 } 60 61 // Account state 62 63 func (qs *queryServer) GetAccount(ctx context.Context, param *GetAccountParam) (*acm.Account, error) { 64 acc, err := qs.state.GetAccount(param.Address) 65 if acc == nil { 66 acc = &acm.Account{} 67 } 68 return acc, err 69 } 70 71 // GetMetadata returns empty metadata string if not found. Metadata can be retrieved by account, or 72 // by metadata hash 73 func (qs *queryServer) GetMetadata(ctx context.Context, param *GetMetadataParam) (*MetadataResult, error) { 74 metadata := &MetadataResult{} 75 var contractMeta *acm.ContractMeta 76 var err error 77 if param.Address != nil { 78 acc, err := qs.state.GetAccount(*param.Address) 79 if err != nil { 80 return metadata, err 81 } 82 if acc != nil && acc.CodeHash != nil { 83 codehash := acc.CodeHash 84 if acc.Forebear != nil { 85 acc, err = qs.state.GetAccount(*acc.Forebear) 86 if err != nil { 87 return metadata, err 88 } 89 } 90 91 for _, m := range acc.ContractMeta { 92 if bytes.Equal(m.CodeHash, codehash) { 93 contractMeta = m 94 break 95 } 96 } 97 98 if contractMeta == nil { 99 deployCodehash := compile.GetDeployCodeHash(acc.EVMCode, *param.Address) 100 for _, m := range acc.ContractMeta { 101 if bytes.Equal(m.CodeHash, deployCodehash) { 102 contractMeta = m 103 break 104 } 105 } 106 } 107 } 108 } else if param.MetadataHash != nil { 109 contractMeta = &acm.ContractMeta{ 110 MetadataHash: *param.MetadataHash, 111 } 112 } 113 if contractMeta == nil { 114 return metadata, nil 115 } 116 if contractMeta.Metadata != "" { 117 // Looks like the metadata is already memoised - (e.g. by native.State) 118 metadata.Metadata = contractMeta.Metadata 119 } else { 120 var metadataHash acmstate.MetadataHash 121 copy(metadataHash[:], contractMeta.MetadataHash) 122 metadata.Metadata, err = qs.state.GetMetadata(metadataHash) 123 } 124 return metadata, err 125 } 126 127 func (qs *queryServer) GetStorage(ctx context.Context, param *GetStorageParam) (*StorageValue, error) { 128 val, err := qs.state.GetStorage(param.Address, param.Key) 129 return &StorageValue{Value: val}, err 130 } 131 132 func (qs *queryServer) ListAccounts(param *ListAccountsParam, stream Query_ListAccountsServer) error { 133 qry, err := query.NewOrEmpty(param.Query) 134 if err != nil { 135 return err 136 } 137 var streamErr error 138 err = qs.state.IterateAccounts(func(acc *acm.Account) error { 139 if qry.Matches(acc) { 140 return stream.Send(acc) 141 } else { 142 return nil 143 } 144 }) 145 if err != nil { 146 return err 147 } 148 return streamErr 149 } 150 151 // Names 152 153 func (qs *queryServer) GetName(ctx context.Context, param *GetNameParam) (entry *names.Entry, err error) { 154 entry, err = qs.state.GetName(param.Name) 155 if entry == nil && err == nil { 156 err = status.Error(codes.NotFound, fmt.Sprintf("name %s not found", param.Name)) 157 } 158 return 159 } 160 161 func (qs *queryServer) ListNames(param *ListNamesParam, stream Query_ListNamesServer) error { 162 qry, err := query.NewOrEmpty(param.Query) 163 if err != nil { 164 return err 165 } 166 var streamErr error 167 err = qs.state.IterateNames(func(entry *names.Entry) error { 168 if qry.Matches(entry) { 169 return stream.Send(entry) 170 } else { 171 return nil 172 } 173 }) 174 if err != nil { 175 return err 176 } 177 return streamErr 178 } 179 180 // Validators 181 182 func (qs *queryServer) GetValidatorSet(ctx context.Context, param *GetValidatorSetParam) (*ValidatorSet, error) { 183 set := validator.Copy(qs.state.Validators(0)) 184 return &ValidatorSet{ 185 Set: set.Validators(), 186 }, nil 187 } 188 189 func (qs *queryServer) GetValidatorSetHistory(ctx context.Context, param *GetValidatorSetHistoryParam) (*ValidatorSetHistory, error) { 190 lookback := int(param.IncludePrevious) 191 switch { 192 case lookback == 0: 193 lookback = 1 194 case lookback < 0 || lookback > state.DefaultValidatorsWindowSize: 195 lookback = state.DefaultValidatorsWindowSize 196 } 197 height := qs.blockchain.LastBlockHeight() 198 if height < uint64(lookback) { 199 lookback = int(height) 200 } 201 history := &ValidatorSetHistory{} 202 for i := 0; i < lookback; i++ { 203 set := validator.Copy(qs.state.Validators(i)) 204 vs := &ValidatorSet{ 205 Height: height - uint64(i), 206 Set: set.Validators(), 207 } 208 history.History = append(history.History, vs) 209 } 210 return history, nil 211 } 212 213 func (qs *queryServer) GetNetworkRegistry(ctx context.Context, param *GetNetworkRegistryParam) (*NetworkRegistry, error) { 214 rv := make([]*RegisteredValidator, 0) 215 err := qs.state.IterateNodes(func(id crypto.Address, rn *registry.NodeIdentity) error { 216 rv = append(rv, &RegisteredValidator{ 217 Address: rn.ValidatorPublicKey.GetAddress(), 218 Node: rn, 219 }) 220 return nil 221 }) 222 return &NetworkRegistry{Set: rv}, err 223 } 224 225 // Proposals 226 227 func (qs *queryServer) GetProposal(ctx context.Context, param *GetProposalParam) (proposal *payload.Ballot, err error) { 228 proposal, err = qs.state.GetProposal(param.Hash) 229 if proposal == nil && err == nil { 230 err = fmt.Errorf("proposal %x not found", param.Hash) 231 } 232 return 233 } 234 235 func (qs *queryServer) ListProposals(param *ListProposalsParam, stream Query_ListProposalsServer) error { 236 var streamErr error 237 err := qs.state.IterateProposals(func(hash []byte, ballot *payload.Ballot) error { 238 if !param.GetProposed() || ballot.ProposalState == payload.Ballot_PROPOSED { 239 return stream.Send(&ProposalResult{Hash: hash, Ballot: ballot}) 240 } else { 241 return nil 242 } 243 }) 244 if err != nil { 245 return err 246 } 247 return streamErr 248 } 249 250 func (qs *queryServer) GetStats(ctx context.Context, param *GetStatsParam) (*Stats, error) { 251 stats := qs.state.GetAccountStats() 252 253 return &Stats{ 254 AccountsWithCode: stats.AccountsWithCode, 255 AccountsWithoutCode: stats.AccountsWithoutCode, 256 }, nil 257 } 258 259 // Tendermint and blocks 260 261 func (qs *queryServer) GetBlockHeader(ctx context.Context, param *GetBlockParam) (*tmproto.Header, error) { 262 header, err := qs.blockchain.GetBlockHeader(param.Height) 263 if err != nil { 264 return nil, err 265 } 266 abciHeader := tmtypes.TM2PB.Header(header) 267 return &abciHeader, nil 268 }