github.com/MetalBlockchain/metalgo@v1.11.9/vms/rpcchainvm/vm_server.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 "os" 12 "time" 13 14 "github.com/prometheus/client_golang/prometheus" 15 "github.com/prometheus/client_golang/prometheus/collectors" 16 "google.golang.org/protobuf/types/known/emptypb" 17 18 "github.com/MetalBlockchain/metalgo/api/keystore/gkeystore" 19 "github.com/MetalBlockchain/metalgo/api/metrics" 20 "github.com/MetalBlockchain/metalgo/chains/atomic/gsharedmemory" 21 "github.com/MetalBlockchain/metalgo/database" 22 "github.com/MetalBlockchain/metalgo/database/corruptabledb" 23 "github.com/MetalBlockchain/metalgo/database/rpcdb" 24 "github.com/MetalBlockchain/metalgo/ids" 25 "github.com/MetalBlockchain/metalgo/ids/galiasreader" 26 "github.com/MetalBlockchain/metalgo/snow" 27 "github.com/MetalBlockchain/metalgo/snow/consensus/snowman" 28 "github.com/MetalBlockchain/metalgo/snow/engine/common" 29 "github.com/MetalBlockchain/metalgo/snow/engine/common/appsender" 30 "github.com/MetalBlockchain/metalgo/snow/engine/snowman/block" 31 "github.com/MetalBlockchain/metalgo/snow/validators/gvalidators" 32 "github.com/MetalBlockchain/metalgo/utils" 33 "github.com/MetalBlockchain/metalgo/utils/crypto/bls" 34 "github.com/MetalBlockchain/metalgo/utils/logging" 35 "github.com/MetalBlockchain/metalgo/utils/wrappers" 36 "github.com/MetalBlockchain/metalgo/version" 37 "github.com/MetalBlockchain/metalgo/vms/platformvm/warp/gwarp" 38 "github.com/MetalBlockchain/metalgo/vms/rpcchainvm/ghttp" 39 "github.com/MetalBlockchain/metalgo/vms/rpcchainvm/grpcutils" 40 "github.com/MetalBlockchain/metalgo/vms/rpcchainvm/messenger" 41 42 aliasreaderpb "github.com/MetalBlockchain/metalgo/proto/pb/aliasreader" 43 appsenderpb "github.com/MetalBlockchain/metalgo/proto/pb/appsender" 44 httppb "github.com/MetalBlockchain/metalgo/proto/pb/http" 45 keystorepb "github.com/MetalBlockchain/metalgo/proto/pb/keystore" 46 messengerpb "github.com/MetalBlockchain/metalgo/proto/pb/messenger" 47 rpcdbpb "github.com/MetalBlockchain/metalgo/proto/pb/rpcdb" 48 sharedmemorypb "github.com/MetalBlockchain/metalgo/proto/pb/sharedmemory" 49 validatorstatepb "github.com/MetalBlockchain/metalgo/proto/pb/validatorstate" 50 vmpb "github.com/MetalBlockchain/metalgo/proto/pb/vm" 51 warppb "github.com/MetalBlockchain/metalgo/proto/pb/warp" 52 grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" 53 ) 54 55 var ( 56 _ vmpb.VMServer = (*VMServer)(nil) 57 58 originalStderr = os.Stderr 59 60 errExpectedBlockWithVerifyContext = errors.New("expected block.WithVerifyContext") 61 ) 62 63 // VMServer is a VM that is managed over RPC. 64 type VMServer struct { 65 vmpb.UnsafeVMServer 66 67 vm block.ChainVM 68 // If nil, the underlying VM doesn't implement the interface. 69 bVM block.BuildBlockWithContextChainVM 70 // If nil, the underlying VM doesn't implement the interface. 71 ssVM block.StateSyncableVM 72 73 allowShutdown *utils.Atomic[bool] 74 75 metrics prometheus.Gatherer 76 db database.Database 77 log logging.Logger 78 79 serverCloser grpcutils.ServerCloser 80 connCloser wrappers.Closer 81 82 ctx *snow.Context 83 closed chan struct{} 84 } 85 86 // NewServer returns a vm instance connected to a remote vm instance 87 func NewServer(vm block.ChainVM, allowShutdown *utils.Atomic[bool]) *VMServer { 88 bVM, _ := vm.(block.BuildBlockWithContextChainVM) 89 ssVM, _ := vm.(block.StateSyncableVM) 90 return &VMServer{ 91 vm: vm, 92 bVM: bVM, 93 ssVM: ssVM, 94 allowShutdown: allowShutdown, 95 } 96 } 97 98 func (vm *VMServer) Initialize(ctx context.Context, req *vmpb.InitializeRequest) (*vmpb.InitializeResponse, error) { 99 subnetID, err := ids.ToID(req.SubnetId) 100 if err != nil { 101 return nil, err 102 } 103 chainID, err := ids.ToID(req.ChainId) 104 if err != nil { 105 return nil, err 106 } 107 nodeID, err := ids.ToNodeID(req.NodeId) 108 if err != nil { 109 return nil, err 110 } 111 publicKey, err := bls.PublicKeyFromCompressedBytes(req.PublicKey) 112 if err != nil { 113 return nil, err 114 } 115 xChainID, err := ids.ToID(req.XChainId) 116 if err != nil { 117 return nil, err 118 } 119 cChainID, err := ids.ToID(req.CChainId) 120 if err != nil { 121 return nil, err 122 } 123 avaxAssetID, err := ids.ToID(req.AvaxAssetId) 124 if err != nil { 125 return nil, err 126 } 127 128 pluginMetrics := metrics.NewPrefixGatherer() 129 vm.metrics = pluginMetrics 130 131 processMetrics, err := metrics.MakeAndRegister( 132 pluginMetrics, 133 "process", 134 ) 135 if err != nil { 136 return nil, err 137 } 138 139 // Current state of process metrics 140 processCollector := collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}) 141 if err := processMetrics.Register(processCollector); err != nil { 142 return nil, err 143 } 144 145 // Go process metrics using debug.GCStats 146 goCollector := collectors.NewGoCollector() 147 if err := processMetrics.Register(goCollector); err != nil { 148 return nil, err 149 } 150 151 grpcMetrics, err := metrics.MakeAndRegister( 152 pluginMetrics, 153 "grpc", 154 ) 155 if err != nil { 156 return nil, err 157 } 158 159 // gRPC client metrics 160 grpcClientMetrics := grpc_prometheus.NewClientMetrics() 161 if err := grpcMetrics.Register(grpcClientMetrics); err != nil { 162 return nil, err 163 } 164 165 vmMetrics := metrics.NewPrefixGatherer() 166 if err := pluginMetrics.Register("vm", vmMetrics); err != nil { 167 return nil, err 168 } 169 170 // Dial the database 171 dbClientConn, err := grpcutils.Dial( 172 req.DbServerAddr, 173 grpcutils.WithChainUnaryInterceptor(grpcClientMetrics.UnaryClientInterceptor()), 174 grpcutils.WithChainStreamInterceptor(grpcClientMetrics.StreamClientInterceptor()), 175 ) 176 if err != nil { 177 return nil, err 178 } 179 vm.connCloser.Add(dbClientConn) 180 vm.db = corruptabledb.New( 181 rpcdb.NewClient(rpcdbpb.NewDatabaseClient(dbClientConn)), 182 ) 183 184 // TODO: Allow the logger to be configured by the client 185 vm.log = logging.NewLogger( 186 fmt.Sprintf("<%s Chain>", chainID), 187 logging.NewWrappedCore( 188 logging.Info, 189 originalStderr, 190 logging.Colors.ConsoleEncoder(), 191 ), 192 ) 193 194 clientConn, err := grpcutils.Dial( 195 req.ServerAddr, 196 grpcutils.WithChainUnaryInterceptor(grpcClientMetrics.UnaryClientInterceptor()), 197 grpcutils.WithChainStreamInterceptor(grpcClientMetrics.StreamClientInterceptor()), 198 ) 199 if err != nil { 200 // Ignore closing errors to return the original error 201 _ = vm.connCloser.Close() 202 return nil, err 203 } 204 205 vm.connCloser.Add(clientConn) 206 207 msgClient := messenger.NewClient(messengerpb.NewMessengerClient(clientConn)) 208 keystoreClient := gkeystore.NewClient(keystorepb.NewKeystoreClient(clientConn)) 209 sharedMemoryClient := gsharedmemory.NewClient(sharedmemorypb.NewSharedMemoryClient(clientConn)) 210 bcLookupClient := galiasreader.NewClient(aliasreaderpb.NewAliasReaderClient(clientConn)) 211 appSenderClient := appsender.NewClient(appsenderpb.NewAppSenderClient(clientConn)) 212 validatorStateClient := gvalidators.NewClient(validatorstatepb.NewValidatorStateClient(clientConn)) 213 warpSignerClient := gwarp.NewClient(warppb.NewSignerClient(clientConn)) 214 215 toEngine := make(chan common.Message, 1) 216 vm.closed = make(chan struct{}) 217 go func() { 218 for { 219 select { 220 case msg, ok := <-toEngine: 221 if !ok { 222 return 223 } 224 // Nothing to do with the error within the goroutine 225 _ = msgClient.Notify(msg) 226 case <-vm.closed: 227 return 228 } 229 } 230 }() 231 232 vm.ctx = &snow.Context{ 233 NetworkID: req.NetworkId, 234 SubnetID: subnetID, 235 ChainID: chainID, 236 NodeID: nodeID, 237 PublicKey: publicKey, 238 239 XChainID: xChainID, 240 CChainID: cChainID, 241 AVAXAssetID: avaxAssetID, 242 243 Log: vm.log, 244 Keystore: keystoreClient, 245 SharedMemory: sharedMemoryClient, 246 BCLookup: bcLookupClient, 247 Metrics: vmMetrics, 248 249 // Signs warp messages 250 WarpSigner: warpSignerClient, 251 252 ValidatorState: validatorStateClient, 253 // TODO: support remaining snowman++ fields 254 255 ChainDataDir: req.ChainDataDir, 256 } 257 258 if err := vm.vm.Initialize(ctx, vm.ctx, vm.db, req.GenesisBytes, req.UpgradeBytes, req.ConfigBytes, toEngine, nil, appSenderClient); err != nil { 259 // Ignore errors closing resources to return the original error 260 _ = vm.connCloser.Close() 261 close(vm.closed) 262 return nil, err 263 } 264 265 lastAccepted, err := vm.vm.LastAccepted(ctx) 266 if err != nil { 267 // Ignore errors closing resources to return the original error 268 _ = vm.vm.Shutdown(ctx) 269 _ = vm.connCloser.Close() 270 close(vm.closed) 271 return nil, err 272 } 273 274 blk, err := vm.vm.GetBlock(ctx, lastAccepted) 275 if err != nil { 276 // Ignore errors closing resources to return the original error 277 _ = vm.vm.Shutdown(ctx) 278 _ = vm.connCloser.Close() 279 close(vm.closed) 280 return nil, err 281 } 282 parentID := blk.Parent() 283 return &vmpb.InitializeResponse{ 284 LastAcceptedId: lastAccepted[:], 285 LastAcceptedParentId: parentID[:], 286 Height: blk.Height(), 287 Bytes: blk.Bytes(), 288 Timestamp: grpcutils.TimestampFromTime(blk.Timestamp()), 289 }, nil 290 } 291 292 func (vm *VMServer) SetState(ctx context.Context, stateReq *vmpb.SetStateRequest) (*vmpb.SetStateResponse, error) { 293 err := vm.vm.SetState(ctx, snow.State(stateReq.State)) 294 if err != nil { 295 return nil, err 296 } 297 298 lastAccepted, err := vm.vm.LastAccepted(ctx) 299 if err != nil { 300 return nil, err 301 } 302 303 blk, err := vm.vm.GetBlock(ctx, lastAccepted) 304 if err != nil { 305 return nil, err 306 } 307 308 parentID := blk.Parent() 309 return &vmpb.SetStateResponse{ 310 LastAcceptedId: lastAccepted[:], 311 LastAcceptedParentId: parentID[:], 312 Height: blk.Height(), 313 Bytes: blk.Bytes(), 314 Timestamp: grpcutils.TimestampFromTime(blk.Timestamp()), 315 }, nil 316 } 317 318 func (vm *VMServer) Shutdown(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) { 319 vm.allowShutdown.Set(true) 320 if vm.closed == nil { 321 return &emptypb.Empty{}, nil 322 } 323 errs := wrappers.Errs{} 324 errs.Add(vm.vm.Shutdown(ctx)) 325 close(vm.closed) 326 vm.serverCloser.Stop() 327 errs.Add(vm.connCloser.Close()) 328 return &emptypb.Empty{}, errs.Err 329 } 330 331 func (vm *VMServer) CreateHandlers(ctx context.Context, _ *emptypb.Empty) (*vmpb.CreateHandlersResponse, error) { 332 handlers, err := vm.vm.CreateHandlers(ctx) 333 if err != nil { 334 return nil, err 335 } 336 resp := &vmpb.CreateHandlersResponse{} 337 for prefix, handler := range handlers { 338 serverListener, err := grpcutils.NewListener() 339 if err != nil { 340 return nil, err 341 } 342 server := grpcutils.NewServer() 343 vm.serverCloser.Add(server) 344 httppb.RegisterHTTPServer(server, ghttp.NewServer(handler)) 345 346 // Start HTTP service 347 go grpcutils.Serve(serverListener, server) 348 349 resp.Handlers = append(resp.Handlers, &vmpb.Handler{ 350 Prefix: prefix, 351 ServerAddr: serverListener.Addr().String(), 352 }) 353 } 354 return resp, nil 355 } 356 357 func (vm *VMServer) Connected(ctx context.Context, req *vmpb.ConnectedRequest) (*emptypb.Empty, error) { 358 nodeID, err := ids.ToNodeID(req.NodeId) 359 if err != nil { 360 return nil, err 361 } 362 363 peerVersion := &version.Application{ 364 Name: req.Name, 365 Major: int(req.Major), 366 Minor: int(req.Minor), 367 Patch: int(req.Patch), 368 } 369 return &emptypb.Empty{}, vm.vm.Connected(ctx, nodeID, peerVersion) 370 } 371 372 func (vm *VMServer) Disconnected(ctx context.Context, req *vmpb.DisconnectedRequest) (*emptypb.Empty, error) { 373 nodeID, err := ids.ToNodeID(req.NodeId) 374 if err != nil { 375 return nil, err 376 } 377 return &emptypb.Empty{}, vm.vm.Disconnected(ctx, nodeID) 378 } 379 380 // If the underlying VM doesn't actually implement this method, its [BuildBlock] 381 // method will be called instead. 382 func (vm *VMServer) BuildBlock(ctx context.Context, req *vmpb.BuildBlockRequest) (*vmpb.BuildBlockResponse, error) { 383 var ( 384 blk snowman.Block 385 err error 386 ) 387 if vm.bVM == nil || req.PChainHeight == nil { 388 blk, err = vm.vm.BuildBlock(ctx) 389 } else { 390 blk, err = vm.bVM.BuildBlockWithContext(ctx, &block.Context{ 391 PChainHeight: *req.PChainHeight, 392 }) 393 } 394 if err != nil { 395 return nil, err 396 } 397 398 blkWithCtx, verifyWithCtx := blk.(block.WithVerifyContext) 399 if verifyWithCtx { 400 verifyWithCtx, err = blkWithCtx.ShouldVerifyWithContext(ctx) 401 if err != nil { 402 return nil, err 403 } 404 } 405 406 var ( 407 blkID = blk.ID() 408 parentID = blk.Parent() 409 ) 410 return &vmpb.BuildBlockResponse{ 411 Id: blkID[:], 412 ParentId: parentID[:], 413 Bytes: blk.Bytes(), 414 Height: blk.Height(), 415 Timestamp: grpcutils.TimestampFromTime(blk.Timestamp()), 416 VerifyWithContext: verifyWithCtx, 417 }, nil 418 } 419 420 func (vm *VMServer) ParseBlock(ctx context.Context, req *vmpb.ParseBlockRequest) (*vmpb.ParseBlockResponse, error) { 421 blk, err := vm.vm.ParseBlock(ctx, req.Bytes) 422 if err != nil { 423 return nil, err 424 } 425 426 blkWithCtx, verifyWithCtx := blk.(block.WithVerifyContext) 427 if verifyWithCtx { 428 verifyWithCtx, err = blkWithCtx.ShouldVerifyWithContext(ctx) 429 if err != nil { 430 return nil, err 431 } 432 } 433 434 var ( 435 blkID = blk.ID() 436 parentID = blk.Parent() 437 ) 438 return &vmpb.ParseBlockResponse{ 439 Id: blkID[:], 440 ParentId: parentID[:], 441 Status: vmpb.Status(blk.Status()), 442 Height: blk.Height(), 443 Timestamp: grpcutils.TimestampFromTime(blk.Timestamp()), 444 VerifyWithContext: verifyWithCtx, 445 }, nil 446 } 447 448 func (vm *VMServer) GetBlock(ctx context.Context, req *vmpb.GetBlockRequest) (*vmpb.GetBlockResponse, error) { 449 id, err := ids.ToID(req.Id) 450 if err != nil { 451 return nil, err 452 } 453 blk, err := vm.vm.GetBlock(ctx, id) 454 if err != nil { 455 return &vmpb.GetBlockResponse{ 456 Err: errorToErrEnum[err], 457 }, errorToRPCError(err) 458 } 459 460 blkWithCtx, verifyWithCtx := blk.(block.WithVerifyContext) 461 if verifyWithCtx { 462 verifyWithCtx, err = blkWithCtx.ShouldVerifyWithContext(ctx) 463 if err != nil { 464 return nil, err 465 } 466 } 467 468 parentID := blk.Parent() 469 return &vmpb.GetBlockResponse{ 470 ParentId: parentID[:], 471 Bytes: blk.Bytes(), 472 Status: vmpb.Status(blk.Status()), 473 Height: blk.Height(), 474 Timestamp: grpcutils.TimestampFromTime(blk.Timestamp()), 475 VerifyWithContext: verifyWithCtx, 476 }, nil 477 } 478 479 func (vm *VMServer) SetPreference(ctx context.Context, req *vmpb.SetPreferenceRequest) (*emptypb.Empty, error) { 480 id, err := ids.ToID(req.Id) 481 if err != nil { 482 return nil, err 483 } 484 return &emptypb.Empty{}, vm.vm.SetPreference(ctx, id) 485 } 486 487 func (vm *VMServer) Health(ctx context.Context, _ *emptypb.Empty) (*vmpb.HealthResponse, error) { 488 vmHealth, err := vm.vm.HealthCheck(ctx) 489 if err != nil { 490 return &vmpb.HealthResponse{}, err 491 } 492 dbHealth, err := vm.db.HealthCheck(ctx) 493 if err != nil { 494 return &vmpb.HealthResponse{}, err 495 } 496 report := map[string]interface{}{ 497 "database": dbHealth, 498 "health": vmHealth, 499 } 500 501 details, err := json.Marshal(report) 502 return &vmpb.HealthResponse{ 503 Details: details, 504 }, err 505 } 506 507 func (vm *VMServer) Version(ctx context.Context, _ *emptypb.Empty) (*vmpb.VersionResponse, error) { 508 version, err := vm.vm.Version(ctx) 509 return &vmpb.VersionResponse{ 510 Version: version, 511 }, err 512 } 513 514 func (vm *VMServer) CrossChainAppRequest(ctx context.Context, msg *vmpb.CrossChainAppRequestMsg) (*emptypb.Empty, error) { 515 chainID, err := ids.ToID(msg.ChainId) 516 if err != nil { 517 return nil, err 518 } 519 deadline, err := grpcutils.TimestampAsTime(msg.Deadline) 520 if err != nil { 521 return nil, err 522 } 523 return &emptypb.Empty{}, vm.vm.CrossChainAppRequest(ctx, chainID, msg.RequestId, deadline, msg.Request) 524 } 525 526 func (vm *VMServer) CrossChainAppRequestFailed(ctx context.Context, msg *vmpb.CrossChainAppRequestFailedMsg) (*emptypb.Empty, error) { 527 chainID, err := ids.ToID(msg.ChainId) 528 if err != nil { 529 return nil, err 530 } 531 532 appErr := &common.AppError{ 533 Code: msg.ErrorCode, 534 Message: msg.ErrorMessage, 535 } 536 return &emptypb.Empty{}, vm.vm.CrossChainAppRequestFailed(ctx, chainID, msg.RequestId, appErr) 537 } 538 539 func (vm *VMServer) CrossChainAppResponse(ctx context.Context, msg *vmpb.CrossChainAppResponseMsg) (*emptypb.Empty, error) { 540 chainID, err := ids.ToID(msg.ChainId) 541 if err != nil { 542 return nil, err 543 } 544 return &emptypb.Empty{}, vm.vm.CrossChainAppResponse(ctx, chainID, msg.RequestId, msg.Response) 545 } 546 547 func (vm *VMServer) AppRequest(ctx context.Context, req *vmpb.AppRequestMsg) (*emptypb.Empty, error) { 548 nodeID, err := ids.ToNodeID(req.NodeId) 549 if err != nil { 550 return nil, err 551 } 552 deadline, err := grpcutils.TimestampAsTime(req.Deadline) 553 if err != nil { 554 return nil, err 555 } 556 return &emptypb.Empty{}, vm.vm.AppRequest(ctx, nodeID, req.RequestId, deadline, req.Request) 557 } 558 559 func (vm *VMServer) AppRequestFailed(ctx context.Context, req *vmpb.AppRequestFailedMsg) (*emptypb.Empty, error) { 560 nodeID, err := ids.ToNodeID(req.NodeId) 561 if err != nil { 562 return nil, err 563 } 564 565 appErr := &common.AppError{ 566 Code: req.ErrorCode, 567 Message: req.ErrorMessage, 568 } 569 return &emptypb.Empty{}, vm.vm.AppRequestFailed(ctx, nodeID, req.RequestId, appErr) 570 } 571 572 func (vm *VMServer) AppResponse(ctx context.Context, req *vmpb.AppResponseMsg) (*emptypb.Empty, error) { 573 nodeID, err := ids.ToNodeID(req.NodeId) 574 if err != nil { 575 return nil, err 576 } 577 return &emptypb.Empty{}, vm.vm.AppResponse(ctx, nodeID, req.RequestId, req.Response) 578 } 579 580 func (vm *VMServer) AppGossip(ctx context.Context, req *vmpb.AppGossipMsg) (*emptypb.Empty, error) { 581 nodeID, err := ids.ToNodeID(req.NodeId) 582 if err != nil { 583 return nil, err 584 } 585 return &emptypb.Empty{}, vm.vm.AppGossip(ctx, nodeID, req.Msg) 586 } 587 588 func (vm *VMServer) Gather(context.Context, *emptypb.Empty) (*vmpb.GatherResponse, error) { 589 metrics, err := vm.metrics.Gather() 590 return &vmpb.GatherResponse{MetricFamilies: metrics}, err 591 } 592 593 func (vm *VMServer) GetAncestors(ctx context.Context, req *vmpb.GetAncestorsRequest) (*vmpb.GetAncestorsResponse, error) { 594 blkID, err := ids.ToID(req.BlkId) 595 if err != nil { 596 return nil, err 597 } 598 maxBlksNum := int(req.MaxBlocksNum) 599 maxBlksSize := int(req.MaxBlocksSize) 600 maxBlocksRetrivalTime := time.Duration(req.MaxBlocksRetrivalTime) 601 602 blocks, err := block.GetAncestors( 603 ctx, 604 vm.log, 605 vm.vm, 606 blkID, 607 maxBlksNum, 608 maxBlksSize, 609 maxBlocksRetrivalTime, 610 ) 611 return &vmpb.GetAncestorsResponse{ 612 BlksBytes: blocks, 613 }, err 614 } 615 616 func (vm *VMServer) BatchedParseBlock( 617 ctx context.Context, 618 req *vmpb.BatchedParseBlockRequest, 619 ) (*vmpb.BatchedParseBlockResponse, error) { 620 blocks := make([]*vmpb.ParseBlockResponse, len(req.Request)) 621 for i, blockBytes := range req.Request { 622 block, err := vm.ParseBlock(ctx, &vmpb.ParseBlockRequest{ 623 Bytes: blockBytes, 624 }) 625 if err != nil { 626 return nil, err 627 } 628 blocks[i] = block 629 } 630 return &vmpb.BatchedParseBlockResponse{ 631 Response: blocks, 632 }, nil 633 } 634 635 func (vm *VMServer) GetBlockIDAtHeight( 636 ctx context.Context, 637 req *vmpb.GetBlockIDAtHeightRequest, 638 ) (*vmpb.GetBlockIDAtHeightResponse, error) { 639 blkID, err := vm.vm.GetBlockIDAtHeight(ctx, req.Height) 640 return &vmpb.GetBlockIDAtHeightResponse{ 641 BlkId: blkID[:], 642 Err: errorToErrEnum[err], 643 }, errorToRPCError(err) 644 } 645 646 func (vm *VMServer) StateSyncEnabled(ctx context.Context, _ *emptypb.Empty) (*vmpb.StateSyncEnabledResponse, error) { 647 var ( 648 enabled bool 649 err error 650 ) 651 if vm.ssVM != nil { 652 enabled, err = vm.ssVM.StateSyncEnabled(ctx) 653 } 654 655 return &vmpb.StateSyncEnabledResponse{ 656 Enabled: enabled, 657 Err: errorToErrEnum[err], 658 }, errorToRPCError(err) 659 } 660 661 func (vm *VMServer) GetOngoingSyncStateSummary( 662 ctx context.Context, 663 _ *emptypb.Empty, 664 ) (*vmpb.GetOngoingSyncStateSummaryResponse, error) { 665 var ( 666 summary block.StateSummary 667 err error 668 ) 669 if vm.ssVM != nil { 670 summary, err = vm.ssVM.GetOngoingSyncStateSummary(ctx) 671 } else { 672 err = block.ErrStateSyncableVMNotImplemented 673 } 674 675 if err != nil { 676 return &vmpb.GetOngoingSyncStateSummaryResponse{ 677 Err: errorToErrEnum[err], 678 }, errorToRPCError(err) 679 } 680 681 summaryID := summary.ID() 682 return &vmpb.GetOngoingSyncStateSummaryResponse{ 683 Id: summaryID[:], 684 Height: summary.Height(), 685 Bytes: summary.Bytes(), 686 }, nil 687 } 688 689 func (vm *VMServer) GetLastStateSummary(ctx context.Context, _ *emptypb.Empty) (*vmpb.GetLastStateSummaryResponse, error) { 690 var ( 691 summary block.StateSummary 692 err error 693 ) 694 if vm.ssVM != nil { 695 summary, err = vm.ssVM.GetLastStateSummary(ctx) 696 } else { 697 err = block.ErrStateSyncableVMNotImplemented 698 } 699 700 if err != nil { 701 return &vmpb.GetLastStateSummaryResponse{ 702 Err: errorToErrEnum[err], 703 }, errorToRPCError(err) 704 } 705 706 summaryID := summary.ID() 707 return &vmpb.GetLastStateSummaryResponse{ 708 Id: summaryID[:], 709 Height: summary.Height(), 710 Bytes: summary.Bytes(), 711 }, nil 712 } 713 714 func (vm *VMServer) ParseStateSummary( 715 ctx context.Context, 716 req *vmpb.ParseStateSummaryRequest, 717 ) (*vmpb.ParseStateSummaryResponse, error) { 718 var ( 719 summary block.StateSummary 720 err error 721 ) 722 if vm.ssVM != nil { 723 summary, err = vm.ssVM.ParseStateSummary(ctx, req.Bytes) 724 } else { 725 err = block.ErrStateSyncableVMNotImplemented 726 } 727 728 if err != nil { 729 return &vmpb.ParseStateSummaryResponse{ 730 Err: errorToErrEnum[err], 731 }, errorToRPCError(err) 732 } 733 734 summaryID := summary.ID() 735 return &vmpb.ParseStateSummaryResponse{ 736 Id: summaryID[:], 737 Height: summary.Height(), 738 }, nil 739 } 740 741 func (vm *VMServer) GetStateSummary( 742 ctx context.Context, 743 req *vmpb.GetStateSummaryRequest, 744 ) (*vmpb.GetStateSummaryResponse, error) { 745 var ( 746 summary block.StateSummary 747 err error 748 ) 749 if vm.ssVM != nil { 750 summary, err = vm.ssVM.GetStateSummary(ctx, req.Height) 751 } else { 752 err = block.ErrStateSyncableVMNotImplemented 753 } 754 755 if err != nil { 756 return &vmpb.GetStateSummaryResponse{ 757 Err: errorToErrEnum[err], 758 }, errorToRPCError(err) 759 } 760 761 summaryID := summary.ID() 762 return &vmpb.GetStateSummaryResponse{ 763 Id: summaryID[:], 764 Bytes: summary.Bytes(), 765 }, nil 766 } 767 768 func (vm *VMServer) BlockVerify(ctx context.Context, req *vmpb.BlockVerifyRequest) (*vmpb.BlockVerifyResponse, error) { 769 blk, err := vm.vm.ParseBlock(ctx, req.Bytes) 770 if err != nil { 771 return nil, err 772 } 773 774 if req.PChainHeight == nil { 775 err = blk.Verify(ctx) 776 } else { 777 blkWithCtx, ok := blk.(block.WithVerifyContext) 778 if !ok { 779 return nil, fmt.Errorf("%w but got %T", errExpectedBlockWithVerifyContext, blk) 780 } 781 blockCtx := &block.Context{ 782 PChainHeight: *req.PChainHeight, 783 } 784 err = blkWithCtx.VerifyWithContext(ctx, blockCtx) 785 } 786 if err != nil { 787 return nil, err 788 } 789 790 return &vmpb.BlockVerifyResponse{ 791 Timestamp: grpcutils.TimestampFromTime(blk.Timestamp()), 792 }, nil 793 } 794 795 func (vm *VMServer) BlockAccept(ctx context.Context, req *vmpb.BlockAcceptRequest) (*emptypb.Empty, error) { 796 id, err := ids.ToID(req.Id) 797 if err != nil { 798 return nil, err 799 } 800 blk, err := vm.vm.GetBlock(ctx, id) 801 if err != nil { 802 return nil, err 803 } 804 if err := blk.Accept(ctx); err != nil { 805 return nil, err 806 } 807 return &emptypb.Empty{}, nil 808 } 809 810 func (vm *VMServer) BlockReject(ctx context.Context, req *vmpb.BlockRejectRequest) (*emptypb.Empty, error) { 811 id, err := ids.ToID(req.Id) 812 if err != nil { 813 return nil, err 814 } 815 blk, err := vm.vm.GetBlock(ctx, id) 816 if err != nil { 817 return nil, err 818 } 819 if err := blk.Reject(ctx); err != nil { 820 return nil, err 821 } 822 return &emptypb.Empty{}, nil 823 } 824 825 func (vm *VMServer) StateSummaryAccept( 826 ctx context.Context, 827 req *vmpb.StateSummaryAcceptRequest, 828 ) (*vmpb.StateSummaryAcceptResponse, error) { 829 var ( 830 mode = block.StateSyncSkipped 831 err error 832 ) 833 if vm.ssVM != nil { 834 var summary block.StateSummary 835 summary, err = vm.ssVM.ParseStateSummary(ctx, req.Bytes) 836 if err == nil { 837 mode, err = summary.Accept(ctx) 838 } 839 } else { 840 err = block.ErrStateSyncableVMNotImplemented 841 } 842 843 return &vmpb.StateSummaryAcceptResponse{ 844 Mode: vmpb.StateSummaryAcceptResponse_Mode(mode), 845 Err: errorToErrEnum[err], 846 }, errorToRPCError(err) 847 }