github.com/ava-labs/avalanchego@v1.11.11/vms/rpcchainvm/vm_client.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package rpcchainvm 5 6 import ( 7 "context" 8 "encoding/json" 9 "errors" 10 "fmt" 11 "net/http" 12 "time" 13 14 "github.com/prometheus/client_golang/prometheus" 15 "go.uber.org/zap" 16 "google.golang.org/grpc" 17 "google.golang.org/grpc/health" 18 "google.golang.org/protobuf/types/known/emptypb" 19 20 "github.com/ava-labs/avalanchego/api/keystore/gkeystore" 21 "github.com/ava-labs/avalanchego/api/metrics" 22 "github.com/ava-labs/avalanchego/chains/atomic/gsharedmemory" 23 "github.com/ava-labs/avalanchego/database" 24 "github.com/ava-labs/avalanchego/database/rpcdb" 25 "github.com/ava-labs/avalanchego/ids" 26 "github.com/ava-labs/avalanchego/ids/galiasreader" 27 "github.com/ava-labs/avalanchego/snow" 28 "github.com/ava-labs/avalanchego/snow/consensus/snowman" 29 "github.com/ava-labs/avalanchego/snow/engine/common" 30 "github.com/ava-labs/avalanchego/snow/engine/common/appsender" 31 "github.com/ava-labs/avalanchego/snow/engine/snowman/block" 32 "github.com/ava-labs/avalanchego/snow/validators/gvalidators" 33 "github.com/ava-labs/avalanchego/utils/crypto/bls" 34 "github.com/ava-labs/avalanchego/utils/resource" 35 "github.com/ava-labs/avalanchego/utils/units" 36 "github.com/ava-labs/avalanchego/utils/wrappers" 37 "github.com/ava-labs/avalanchego/version" 38 "github.com/ava-labs/avalanchego/vms/components/chain" 39 "github.com/ava-labs/avalanchego/vms/platformvm/warp/gwarp" 40 "github.com/ava-labs/avalanchego/vms/rpcchainvm/ghttp" 41 "github.com/ava-labs/avalanchego/vms/rpcchainvm/grpcutils" 42 "github.com/ava-labs/avalanchego/vms/rpcchainvm/messenger" 43 "github.com/ava-labs/avalanchego/vms/rpcchainvm/runtime" 44 45 aliasreaderpb "github.com/ava-labs/avalanchego/proto/pb/aliasreader" 46 appsenderpb "github.com/ava-labs/avalanchego/proto/pb/appsender" 47 httppb "github.com/ava-labs/avalanchego/proto/pb/http" 48 keystorepb "github.com/ava-labs/avalanchego/proto/pb/keystore" 49 messengerpb "github.com/ava-labs/avalanchego/proto/pb/messenger" 50 rpcdbpb "github.com/ava-labs/avalanchego/proto/pb/rpcdb" 51 sharedmemorypb "github.com/ava-labs/avalanchego/proto/pb/sharedmemory" 52 validatorstatepb "github.com/ava-labs/avalanchego/proto/pb/validatorstate" 53 vmpb "github.com/ava-labs/avalanchego/proto/pb/vm" 54 warppb "github.com/ava-labs/avalanchego/proto/pb/warp" 55 grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" 56 dto "github.com/prometheus/client_model/go" 57 healthpb "google.golang.org/grpc/health/grpc_health_v1" 58 ) 59 60 // TODO: Enable these to be configured by the user 61 const ( 62 decidedCacheSize = 64 * units.MiB 63 missingCacheSize = 2048 64 unverifiedCacheSize = 64 * units.MiB 65 bytesToIDCacheSize = 64 * units.MiB 66 ) 67 68 var ( 69 errUnsupportedFXs = errors.New("unsupported feature extensions") 70 errBatchedParseBlockWrongNumberOfBlocks = errors.New("BatchedParseBlock returned different number of blocks than expected") 71 72 _ block.ChainVM = (*VMClient)(nil) 73 _ block.BuildBlockWithContextChainVM = (*VMClient)(nil) 74 _ block.BatchedChainVM = (*VMClient)(nil) 75 _ block.StateSyncableVM = (*VMClient)(nil) 76 _ prometheus.Gatherer = (*VMClient)(nil) 77 78 _ snowman.Block = (*blockClient)(nil) 79 _ block.WithVerifyContext = (*blockClient)(nil) 80 81 _ block.StateSummary = (*summaryClient)(nil) 82 ) 83 84 // VMClient is an implementation of a VM that talks over RPC. 85 type VMClient struct { 86 *chain.State 87 client vmpb.VMClient 88 runtime runtime.Stopper 89 pid int 90 processTracker resource.ProcessTracker 91 metricsGatherer metrics.MultiGatherer 92 93 messenger *messenger.Server 94 keystore *gkeystore.Server 95 sharedMemory *gsharedmemory.Server 96 bcLookup *galiasreader.Server 97 appSender *appsender.Server 98 validatorStateServer *gvalidators.Server 99 warpSignerServer *gwarp.Server 100 101 serverCloser grpcutils.ServerCloser 102 conns []*grpc.ClientConn 103 104 grpcServerMetrics *grpc_prometheus.ServerMetrics 105 } 106 107 // NewClient returns a VM connected to a remote VM 108 func NewClient( 109 clientConn *grpc.ClientConn, 110 runtime runtime.Stopper, 111 pid int, 112 processTracker resource.ProcessTracker, 113 metricsGatherer metrics.MultiGatherer, 114 ) *VMClient { 115 return &VMClient{ 116 client: vmpb.NewVMClient(clientConn), 117 runtime: runtime, 118 pid: pid, 119 processTracker: processTracker, 120 metricsGatherer: metricsGatherer, 121 conns: []*grpc.ClientConn{clientConn}, 122 } 123 } 124 125 func (vm *VMClient) Initialize( 126 ctx context.Context, 127 chainCtx *snow.Context, 128 db database.Database, 129 genesisBytes []byte, 130 upgradeBytes []byte, 131 configBytes []byte, 132 toEngine chan<- common.Message, 133 fxs []*common.Fx, 134 appSender common.AppSender, 135 ) error { 136 if len(fxs) != 0 { 137 return errUnsupportedFXs 138 } 139 140 primaryAlias, err := chainCtx.BCLookup.PrimaryAlias(chainCtx.ChainID) 141 if err != nil { 142 // If fetching the alias fails, we default to the chain's ID 143 primaryAlias = chainCtx.ChainID.String() 144 } 145 146 // Register metrics 147 serverReg, err := metrics.MakeAndRegister( 148 vm.metricsGatherer, 149 primaryAlias, 150 ) 151 if err != nil { 152 return err 153 } 154 vm.grpcServerMetrics = grpc_prometheus.NewServerMetrics() 155 if err := serverReg.Register(vm.grpcServerMetrics); err != nil { 156 return err 157 } 158 159 if err := chainCtx.Metrics.Register("", vm); err != nil { 160 return err 161 } 162 163 // Initialize the database 164 dbServerListener, err := grpcutils.NewListener() 165 if err != nil { 166 return err 167 } 168 dbServerAddr := dbServerListener.Addr().String() 169 170 go grpcutils.Serve(dbServerListener, vm.newDBServer(db)) 171 chainCtx.Log.Info("grpc: serving database", 172 zap.String("address", dbServerAddr), 173 ) 174 175 vm.messenger = messenger.NewServer(toEngine) 176 vm.keystore = gkeystore.NewServer(chainCtx.Keystore) 177 vm.sharedMemory = gsharedmemory.NewServer(chainCtx.SharedMemory, db) 178 vm.bcLookup = galiasreader.NewServer(chainCtx.BCLookup) 179 vm.appSender = appsender.NewServer(appSender) 180 vm.validatorStateServer = gvalidators.NewServer(chainCtx.ValidatorState) 181 vm.warpSignerServer = gwarp.NewServer(chainCtx.WarpSigner) 182 183 serverListener, err := grpcutils.NewListener() 184 if err != nil { 185 return err 186 } 187 serverAddr := serverListener.Addr().String() 188 189 go grpcutils.Serve(serverListener, vm.newInitServer()) 190 chainCtx.Log.Info("grpc: serving vm services", 191 zap.String("address", serverAddr), 192 ) 193 194 networkUpgrades := &vmpb.NetworkUpgrades{ 195 ApricotPhase_1Time: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.ApricotPhase1Time), 196 ApricotPhase_2Time: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.ApricotPhase2Time), 197 ApricotPhase_3Time: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.ApricotPhase3Time), 198 ApricotPhase_4Time: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.ApricotPhase4Time), 199 ApricotPhase_4MinPChainHeight: chainCtx.NetworkUpgrades.ApricotPhase4MinPChainHeight, 200 ApricotPhase_5Time: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.ApricotPhase5Time), 201 ApricotPhasePre_6Time: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.ApricotPhasePre6Time), 202 ApricotPhase_6Time: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.ApricotPhase6Time), 203 ApricotPhasePost_6Time: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.ApricotPhasePost6Time), 204 BanffTime: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.BanffTime), 205 CortinaTime: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.CortinaTime), 206 CortinaXChainStopVertexId: chainCtx.NetworkUpgrades.CortinaXChainStopVertexID[:], 207 DurangoTime: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.DurangoTime), 208 EtnaTime: grpcutils.TimestampFromTime(chainCtx.NetworkUpgrades.EtnaTime), 209 } 210 211 resp, err := vm.client.Initialize(ctx, &vmpb.InitializeRequest{ 212 NetworkId: chainCtx.NetworkID, 213 SubnetId: chainCtx.SubnetID[:], 214 ChainId: chainCtx.ChainID[:], 215 NodeId: chainCtx.NodeID.Bytes(), 216 PublicKey: bls.PublicKeyToCompressedBytes(chainCtx.PublicKey), 217 NetworkUpgrades: networkUpgrades, 218 XChainId: chainCtx.XChainID[:], 219 CChainId: chainCtx.CChainID[:], 220 AvaxAssetId: chainCtx.AVAXAssetID[:], 221 ChainDataDir: chainCtx.ChainDataDir, 222 GenesisBytes: genesisBytes, 223 UpgradeBytes: upgradeBytes, 224 ConfigBytes: configBytes, 225 DbServerAddr: dbServerAddr, 226 ServerAddr: serverAddr, 227 }) 228 if err != nil { 229 return err 230 } 231 232 id, err := ids.ToID(resp.LastAcceptedId) 233 if err != nil { 234 return err 235 } 236 parentID, err := ids.ToID(resp.LastAcceptedParentId) 237 if err != nil { 238 return err 239 } 240 241 time, err := grpcutils.TimestampAsTime(resp.Timestamp) 242 if err != nil { 243 return err 244 } 245 246 // We don't need to check whether this is a block.WithVerifyContext because 247 // we'll never Verify this block. 248 lastAcceptedBlk := &blockClient{ 249 vm: vm, 250 id: id, 251 parentID: parentID, 252 bytes: resp.Bytes, 253 height: resp.Height, 254 time: time, 255 } 256 257 vm.State, err = chain.NewMeteredState( 258 serverReg, 259 &chain.Config{ 260 DecidedCacheSize: decidedCacheSize, 261 MissingCacheSize: missingCacheSize, 262 UnverifiedCacheSize: unverifiedCacheSize, 263 BytesToIDCacheSize: bytesToIDCacheSize, 264 LastAcceptedBlock: lastAcceptedBlk, 265 GetBlock: vm.getBlock, 266 UnmarshalBlock: vm.parseBlock, 267 BatchedUnmarshalBlock: vm.batchedParseBlock, 268 BuildBlock: vm.buildBlock, 269 BuildBlockWithContext: vm.buildBlockWithContext, 270 }, 271 ) 272 return err 273 } 274 275 func (vm *VMClient) newDBServer(db database.Database) *grpc.Server { 276 server := grpcutils.NewServer( 277 grpcutils.WithUnaryInterceptor(vm.grpcServerMetrics.UnaryServerInterceptor()), 278 grpcutils.WithStreamInterceptor(vm.grpcServerMetrics.StreamServerInterceptor()), 279 ) 280 281 // See https://github.com/grpc/grpc/blob/master/doc/health-checking.md 282 grpcHealth := health.NewServer() 283 grpcHealth.SetServingStatus("", healthpb.HealthCheckResponse_SERVING) 284 285 vm.serverCloser.Add(server) 286 287 // Register services 288 rpcdbpb.RegisterDatabaseServer(server, rpcdb.NewServer(db)) 289 healthpb.RegisterHealthServer(server, grpcHealth) 290 291 // Ensure metric counters are zeroed on restart 292 grpc_prometheus.Register(server) 293 294 return server 295 } 296 297 func (vm *VMClient) newInitServer() *grpc.Server { 298 server := grpcutils.NewServer( 299 grpcutils.WithUnaryInterceptor(vm.grpcServerMetrics.UnaryServerInterceptor()), 300 grpcutils.WithStreamInterceptor(vm.grpcServerMetrics.StreamServerInterceptor()), 301 ) 302 303 // See https://github.com/grpc/grpc/blob/master/doc/health-checking.md 304 grpcHealth := health.NewServer() 305 grpcHealth.SetServingStatus("", healthpb.HealthCheckResponse_SERVING) 306 307 vm.serverCloser.Add(server) 308 309 // Register services 310 messengerpb.RegisterMessengerServer(server, vm.messenger) 311 keystorepb.RegisterKeystoreServer(server, vm.keystore) 312 sharedmemorypb.RegisterSharedMemoryServer(server, vm.sharedMemory) 313 aliasreaderpb.RegisterAliasReaderServer(server, vm.bcLookup) 314 appsenderpb.RegisterAppSenderServer(server, vm.appSender) 315 healthpb.RegisterHealthServer(server, grpcHealth) 316 validatorstatepb.RegisterValidatorStateServer(server, vm.validatorStateServer) 317 warppb.RegisterSignerServer(server, vm.warpSignerServer) 318 319 // Ensure metric counters are zeroed on restart 320 grpc_prometheus.Register(server) 321 322 return server 323 } 324 325 func (vm *VMClient) SetState(ctx context.Context, state snow.State) error { 326 resp, err := vm.client.SetState(ctx, &vmpb.SetStateRequest{ 327 State: vmpb.State(state), 328 }) 329 if err != nil { 330 return err 331 } 332 333 id, err := ids.ToID(resp.LastAcceptedId) 334 if err != nil { 335 return err 336 } 337 338 parentID, err := ids.ToID(resp.LastAcceptedParentId) 339 if err != nil { 340 return err 341 } 342 343 time, err := grpcutils.TimestampAsTime(resp.Timestamp) 344 if err != nil { 345 return err 346 } 347 348 // We don't need to check whether this is a block.WithVerifyContext because 349 // we'll never Verify this block. 350 return vm.State.SetLastAcceptedBlock(&blockClient{ 351 vm: vm, 352 id: id, 353 parentID: parentID, 354 bytes: resp.Bytes, 355 height: resp.Height, 356 time: time, 357 }) 358 } 359 360 func (vm *VMClient) Shutdown(ctx context.Context) error { 361 errs := wrappers.Errs{} 362 _, err := vm.client.Shutdown(ctx, &emptypb.Empty{}) 363 errs.Add(err) 364 365 vm.serverCloser.Stop() 366 for _, conn := range vm.conns { 367 errs.Add(conn.Close()) 368 } 369 370 vm.runtime.Stop(ctx) 371 372 vm.processTracker.UntrackProcess(vm.pid) 373 return errs.Err 374 } 375 376 func (vm *VMClient) CreateHandlers(ctx context.Context) (map[string]http.Handler, error) { 377 resp, err := vm.client.CreateHandlers(ctx, &emptypb.Empty{}) 378 if err != nil { 379 return nil, err 380 } 381 382 handlers := make(map[string]http.Handler, len(resp.Handlers)) 383 for _, handler := range resp.Handlers { 384 clientConn, err := grpcutils.Dial(handler.ServerAddr) 385 if err != nil { 386 return nil, err 387 } 388 389 vm.conns = append(vm.conns, clientConn) 390 handlers[handler.Prefix] = ghttp.NewClient(httppb.NewHTTPClient(clientConn)) 391 } 392 return handlers, nil 393 } 394 395 func (vm *VMClient) Connected(ctx context.Context, nodeID ids.NodeID, nodeVersion *version.Application) error { 396 _, err := vm.client.Connected(ctx, &vmpb.ConnectedRequest{ 397 NodeId: nodeID.Bytes(), 398 Name: nodeVersion.Name, 399 Major: uint32(nodeVersion.Major), 400 Minor: uint32(nodeVersion.Minor), 401 Patch: uint32(nodeVersion.Patch), 402 }) 403 return err 404 } 405 406 func (vm *VMClient) Disconnected(ctx context.Context, nodeID ids.NodeID) error { 407 _, err := vm.client.Disconnected(ctx, &vmpb.DisconnectedRequest{ 408 NodeId: nodeID.Bytes(), 409 }) 410 return err 411 } 412 413 // If the underlying VM doesn't actually implement this method, its [BuildBlock] 414 // method will be called instead. 415 func (vm *VMClient) buildBlockWithContext(ctx context.Context, blockCtx *block.Context) (snowman.Block, error) { 416 resp, err := vm.client.BuildBlock(ctx, &vmpb.BuildBlockRequest{ 417 PChainHeight: &blockCtx.PChainHeight, 418 }) 419 if err != nil { 420 return nil, err 421 } 422 return vm.newBlockFromBuildBlock(resp) 423 } 424 425 func (vm *VMClient) buildBlock(ctx context.Context) (snowman.Block, error) { 426 resp, err := vm.client.BuildBlock(ctx, &vmpb.BuildBlockRequest{}) 427 if err != nil { 428 return nil, err 429 } 430 return vm.newBlockFromBuildBlock(resp) 431 } 432 433 func (vm *VMClient) parseBlock(ctx context.Context, bytes []byte) (snowman.Block, error) { 434 resp, err := vm.client.ParseBlock(ctx, &vmpb.ParseBlockRequest{ 435 Bytes: bytes, 436 }) 437 if err != nil { 438 return nil, err 439 } 440 441 id, err := ids.ToID(resp.Id) 442 if err != nil { 443 return nil, err 444 } 445 446 parentID, err := ids.ToID(resp.ParentId) 447 if err != nil { 448 return nil, err 449 } 450 451 time, err := grpcutils.TimestampAsTime(resp.Timestamp) 452 if err != nil { 453 return nil, err 454 } 455 return &blockClient{ 456 vm: vm, 457 id: id, 458 parentID: parentID, 459 bytes: bytes, 460 height: resp.Height, 461 time: time, 462 shouldVerifyWithCtx: resp.VerifyWithContext, 463 }, nil 464 } 465 466 func (vm *VMClient) getBlock(ctx context.Context, blkID ids.ID) (snowman.Block, error) { 467 resp, err := vm.client.GetBlock(ctx, &vmpb.GetBlockRequest{ 468 Id: blkID[:], 469 }) 470 if err != nil { 471 return nil, err 472 } 473 if errEnum := resp.Err; errEnum != vmpb.Error_ERROR_UNSPECIFIED { 474 return nil, errEnumToError[errEnum] 475 } 476 477 parentID, err := ids.ToID(resp.ParentId) 478 if err != nil { 479 return nil, err 480 } 481 482 time, err := grpcutils.TimestampAsTime(resp.Timestamp) 483 return &blockClient{ 484 vm: vm, 485 id: blkID, 486 parentID: parentID, 487 bytes: resp.Bytes, 488 height: resp.Height, 489 time: time, 490 shouldVerifyWithCtx: resp.VerifyWithContext, 491 }, err 492 } 493 494 func (vm *VMClient) SetPreference(ctx context.Context, blkID ids.ID) error { 495 _, err := vm.client.SetPreference(ctx, &vmpb.SetPreferenceRequest{ 496 Id: blkID[:], 497 }) 498 return err 499 } 500 501 func (vm *VMClient) HealthCheck(ctx context.Context) (interface{}, error) { 502 // HealthCheck is a special case, where we want to fail fast instead of block. 503 failFast := grpc.WaitForReady(false) 504 health, err := vm.client.Health(ctx, &emptypb.Empty{}, failFast) 505 if err != nil { 506 return nil, fmt.Errorf("health check failed: %w", err) 507 } 508 509 return json.RawMessage(health.Details), nil 510 } 511 512 func (vm *VMClient) Version(ctx context.Context) (string, error) { 513 resp, err := vm.client.Version(ctx, &emptypb.Empty{}) 514 if err != nil { 515 return "", err 516 } 517 return resp.Version, nil 518 } 519 520 func (vm *VMClient) AppRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, deadline time.Time, request []byte) error { 521 _, err := vm.client.AppRequest( 522 ctx, 523 &vmpb.AppRequestMsg{ 524 NodeId: nodeID.Bytes(), 525 RequestId: requestID, 526 Request: request, 527 Deadline: grpcutils.TimestampFromTime(deadline), 528 }, 529 ) 530 return err 531 } 532 533 func (vm *VMClient) AppResponse(ctx context.Context, nodeID ids.NodeID, requestID uint32, response []byte) error { 534 _, err := vm.client.AppResponse( 535 ctx, 536 &vmpb.AppResponseMsg{ 537 NodeId: nodeID.Bytes(), 538 RequestId: requestID, 539 Response: response, 540 }, 541 ) 542 return err 543 } 544 545 func (vm *VMClient) AppRequestFailed(ctx context.Context, nodeID ids.NodeID, requestID uint32, appErr *common.AppError) error { 546 msg := &vmpb.AppRequestFailedMsg{ 547 NodeId: nodeID.Bytes(), 548 RequestId: requestID, 549 ErrorCode: appErr.Code, 550 ErrorMessage: appErr.Message, 551 } 552 553 _, err := vm.client.AppRequestFailed(ctx, msg) 554 return err 555 } 556 557 func (vm *VMClient) AppGossip(ctx context.Context, nodeID ids.NodeID, msg []byte) error { 558 _, err := vm.client.AppGossip( 559 ctx, 560 &vmpb.AppGossipMsg{ 561 NodeId: nodeID.Bytes(), 562 Msg: msg, 563 }, 564 ) 565 return err 566 } 567 568 func (vm *VMClient) Gather() ([]*dto.MetricFamily, error) { 569 resp, err := vm.client.Gather(context.Background(), &emptypb.Empty{}) 570 if err != nil { 571 return nil, err 572 } 573 return resp.MetricFamilies, nil 574 } 575 576 func (vm *VMClient) GetAncestors( 577 ctx context.Context, 578 blkID ids.ID, 579 maxBlocksNum int, 580 maxBlocksSize int, 581 maxBlocksRetrivalTime time.Duration, 582 ) ([][]byte, error) { 583 resp, err := vm.client.GetAncestors(ctx, &vmpb.GetAncestorsRequest{ 584 BlkId: blkID[:], 585 MaxBlocksNum: int32(maxBlocksNum), 586 MaxBlocksSize: int32(maxBlocksSize), 587 MaxBlocksRetrivalTime: int64(maxBlocksRetrivalTime), 588 }) 589 if err != nil { 590 return nil, err 591 } 592 return resp.BlksBytes, nil 593 } 594 595 func (vm *VMClient) batchedParseBlock(ctx context.Context, blksBytes [][]byte) ([]snowman.Block, error) { 596 resp, err := vm.client.BatchedParseBlock(ctx, &vmpb.BatchedParseBlockRequest{ 597 Request: blksBytes, 598 }) 599 if err != nil { 600 return nil, err 601 } 602 if len(blksBytes) != len(resp.Response) { 603 return nil, errBatchedParseBlockWrongNumberOfBlocks 604 } 605 606 res := make([]snowman.Block, 0, len(blksBytes)) 607 for idx, blkResp := range resp.Response { 608 id, err := ids.ToID(blkResp.Id) 609 if err != nil { 610 return nil, err 611 } 612 613 parentID, err := ids.ToID(blkResp.ParentId) 614 if err != nil { 615 return nil, err 616 } 617 618 time, err := grpcutils.TimestampAsTime(blkResp.Timestamp) 619 if err != nil { 620 return nil, err 621 } 622 623 res = append(res, &blockClient{ 624 vm: vm, 625 id: id, 626 parentID: parentID, 627 bytes: blksBytes[idx], 628 height: blkResp.Height, 629 time: time, 630 shouldVerifyWithCtx: blkResp.VerifyWithContext, 631 }) 632 } 633 634 return res, nil 635 } 636 637 func (vm *VMClient) GetBlockIDAtHeight(ctx context.Context, height uint64) (ids.ID, error) { 638 resp, err := vm.client.GetBlockIDAtHeight( 639 ctx, 640 &vmpb.GetBlockIDAtHeightRequest{Height: height}, 641 ) 642 if err != nil { 643 return ids.Empty, err 644 } 645 if errEnum := resp.Err; errEnum != vmpb.Error_ERROR_UNSPECIFIED { 646 return ids.Empty, errEnumToError[errEnum] 647 } 648 return ids.ToID(resp.BlkId) 649 } 650 651 func (vm *VMClient) StateSyncEnabled(ctx context.Context) (bool, error) { 652 resp, err := vm.client.StateSyncEnabled(ctx, &emptypb.Empty{}) 653 if err != nil { 654 return false, err 655 } 656 err = errEnumToError[resp.Err] 657 if err == block.ErrStateSyncableVMNotImplemented { 658 return false, nil 659 } 660 return resp.Enabled, err 661 } 662 663 func (vm *VMClient) GetOngoingSyncStateSummary(ctx context.Context) (block.StateSummary, error) { 664 resp, err := vm.client.GetOngoingSyncStateSummary(ctx, &emptypb.Empty{}) 665 if err != nil { 666 return nil, err 667 } 668 if errEnum := resp.Err; errEnum != vmpb.Error_ERROR_UNSPECIFIED { 669 return nil, errEnumToError[errEnum] 670 } 671 672 summaryID, err := ids.ToID(resp.Id) 673 return &summaryClient{ 674 vm: vm, 675 id: summaryID, 676 height: resp.Height, 677 bytes: resp.Bytes, 678 }, err 679 } 680 681 func (vm *VMClient) GetLastStateSummary(ctx context.Context) (block.StateSummary, error) { 682 resp, err := vm.client.GetLastStateSummary(ctx, &emptypb.Empty{}) 683 if err != nil { 684 return nil, err 685 } 686 if errEnum := resp.Err; errEnum != vmpb.Error_ERROR_UNSPECIFIED { 687 return nil, errEnumToError[errEnum] 688 } 689 690 summaryID, err := ids.ToID(resp.Id) 691 return &summaryClient{ 692 vm: vm, 693 id: summaryID, 694 height: resp.Height, 695 bytes: resp.Bytes, 696 }, err 697 } 698 699 func (vm *VMClient) ParseStateSummary(ctx context.Context, summaryBytes []byte) (block.StateSummary, error) { 700 resp, err := vm.client.ParseStateSummary( 701 ctx, 702 &vmpb.ParseStateSummaryRequest{ 703 Bytes: summaryBytes, 704 }, 705 ) 706 if err != nil { 707 return nil, err 708 } 709 if errEnum := resp.Err; errEnum != vmpb.Error_ERROR_UNSPECIFIED { 710 return nil, errEnumToError[errEnum] 711 } 712 713 summaryID, err := ids.ToID(resp.Id) 714 return &summaryClient{ 715 vm: vm, 716 id: summaryID, 717 height: resp.Height, 718 bytes: summaryBytes, 719 }, err 720 } 721 722 func (vm *VMClient) GetStateSummary(ctx context.Context, summaryHeight uint64) (block.StateSummary, error) { 723 resp, err := vm.client.GetStateSummary( 724 ctx, 725 &vmpb.GetStateSummaryRequest{ 726 Height: summaryHeight, 727 }, 728 ) 729 if err != nil { 730 return nil, err 731 } 732 if errEnum := resp.Err; errEnum != vmpb.Error_ERROR_UNSPECIFIED { 733 return nil, errEnumToError[errEnum] 734 } 735 736 summaryID, err := ids.ToID(resp.Id) 737 return &summaryClient{ 738 vm: vm, 739 id: summaryID, 740 height: summaryHeight, 741 bytes: resp.Bytes, 742 }, err 743 } 744 745 func (vm *VMClient) newBlockFromBuildBlock(resp *vmpb.BuildBlockResponse) (*blockClient, error) { 746 id, err := ids.ToID(resp.Id) 747 if err != nil { 748 return nil, err 749 } 750 751 parentID, err := ids.ToID(resp.ParentId) 752 if err != nil { 753 return nil, err 754 } 755 756 time, err := grpcutils.TimestampAsTime(resp.Timestamp) 757 return &blockClient{ 758 vm: vm, 759 id: id, 760 parentID: parentID, 761 bytes: resp.Bytes, 762 height: resp.Height, 763 time: time, 764 shouldVerifyWithCtx: resp.VerifyWithContext, 765 }, err 766 } 767 768 type blockClient struct { 769 vm *VMClient 770 771 id ids.ID 772 parentID ids.ID 773 bytes []byte 774 height uint64 775 time time.Time 776 shouldVerifyWithCtx bool 777 } 778 779 func (b *blockClient) ID() ids.ID { 780 return b.id 781 } 782 783 func (b *blockClient) Accept(ctx context.Context) error { 784 _, err := b.vm.client.BlockAccept(ctx, &vmpb.BlockAcceptRequest{ 785 Id: b.id[:], 786 }) 787 return err 788 } 789 790 func (b *blockClient) Reject(ctx context.Context) error { 791 _, err := b.vm.client.BlockReject(ctx, &vmpb.BlockRejectRequest{ 792 Id: b.id[:], 793 }) 794 return err 795 } 796 797 func (b *blockClient) Parent() ids.ID { 798 return b.parentID 799 } 800 801 func (b *blockClient) Verify(ctx context.Context) error { 802 resp, err := b.vm.client.BlockVerify(ctx, &vmpb.BlockVerifyRequest{ 803 Bytes: b.bytes, 804 }) 805 if err != nil { 806 return err 807 } 808 809 b.time, err = grpcutils.TimestampAsTime(resp.Timestamp) 810 return err 811 } 812 813 func (b *blockClient) Bytes() []byte { 814 return b.bytes 815 } 816 817 func (b *blockClient) Height() uint64 { 818 return b.height 819 } 820 821 func (b *blockClient) Timestamp() time.Time { 822 return b.time 823 } 824 825 func (b *blockClient) ShouldVerifyWithContext(context.Context) (bool, error) { 826 return b.shouldVerifyWithCtx, nil 827 } 828 829 func (b *blockClient) VerifyWithContext(ctx context.Context, blockCtx *block.Context) error { 830 resp, err := b.vm.client.BlockVerify(ctx, &vmpb.BlockVerifyRequest{ 831 Bytes: b.bytes, 832 PChainHeight: &blockCtx.PChainHeight, 833 }) 834 if err != nil { 835 return err 836 } 837 838 b.time, err = grpcutils.TimestampAsTime(resp.Timestamp) 839 return err 840 } 841 842 type summaryClient struct { 843 vm *VMClient 844 845 id ids.ID 846 height uint64 847 bytes []byte 848 } 849 850 func (s *summaryClient) ID() ids.ID { 851 return s.id 852 } 853 854 func (s *summaryClient) Height() uint64 { 855 return s.height 856 } 857 858 func (s *summaryClient) Bytes() []byte { 859 return s.bytes 860 } 861 862 func (s *summaryClient) Accept(ctx context.Context) (block.StateSyncMode, error) { 863 resp, err := s.vm.client.StateSummaryAccept( 864 ctx, 865 &vmpb.StateSummaryAcceptRequest{ 866 Bytes: s.bytes, 867 }, 868 ) 869 if err != nil { 870 return block.StateSyncSkipped, err 871 } 872 return block.StateSyncMode(resp.Mode), errEnumToError[resp.Err] 873 }