github.com/consideritdone/landslidecore@v0.0.0-20230718131026-a8b21c5cf8a7/vm/vm.go (about) 1 package vm 2 3 import ( 4 "context" 5 "encoding/base64" 6 "errors" 7 "fmt" 8 "time" 9 10 "github.com/ava-labs/avalanchego/api/health" 11 "github.com/ava-labs/avalanchego/api/metrics" 12 "github.com/ava-labs/avalanchego/database/manager" 13 "github.com/ava-labs/avalanchego/database/prefixdb" 14 "github.com/ava-labs/avalanchego/ids" 15 "github.com/ava-labs/avalanchego/snow" 16 "github.com/ava-labs/avalanchego/snow/choices" 17 "github.com/ava-labs/avalanchego/snow/consensus/snowman" 18 "github.com/ava-labs/avalanchego/snow/engine/common" 19 "github.com/ava-labs/avalanchego/snow/engine/snowman/block" 20 "github.com/ava-labs/avalanchego/snow/validators" 21 "github.com/ava-labs/avalanchego/utils" 22 "github.com/ava-labs/avalanchego/version" 23 24 abciTypes "github.com/consideritdone/landslidecore/abci/types" 25 "github.com/consideritdone/landslidecore/config" 26 "github.com/consideritdone/landslidecore/consensus" 27 "github.com/consideritdone/landslidecore/crypto/secp256k1" 28 "github.com/consideritdone/landslidecore/crypto/tmhash" 29 "github.com/consideritdone/landslidecore/libs/log" 30 mempl "github.com/consideritdone/landslidecore/mempool" 31 "github.com/consideritdone/landslidecore/node" 32 tmproto "github.com/consideritdone/landslidecore/proto/tendermint/types" 33 "github.com/consideritdone/landslidecore/proxy" 34 rpcserver "github.com/consideritdone/landslidecore/rpc/jsonrpc/server" 35 "github.com/consideritdone/landslidecore/state" 36 "github.com/consideritdone/landslidecore/state/indexer" 37 blockidxkv "github.com/consideritdone/landslidecore/state/indexer/block/kv" 38 "github.com/consideritdone/landslidecore/state/txindex" 39 txidxkv "github.com/consideritdone/landslidecore/state/txindex/kv" 40 "github.com/consideritdone/landslidecore/store" 41 "github.com/consideritdone/landslidecore/types" 42 ) 43 44 const ( 45 Name = "landslide" 46 47 decidedCacheSize = 100 48 missingCacheSize = 50 49 unverifiedCacheSize = 50 50 51 genesisChunkSize = 16 * 1024 * 1024 // 16 52 ) 53 54 var ( 55 Version = version.Semantic{ 56 Major: 0, 57 Minor: 1, 58 Patch: 2, 59 } 60 _ common.NetworkAppHandler = (*VM)(nil) 61 _ common.CrossChainAppHandler = (*VM)(nil) 62 _ common.AppHandler = (*VM)(nil) 63 _ health.Checker = (*VM)(nil) 64 _ validators.Connector = (*VM)(nil) 65 _ common.VM = (*VM)(nil) 66 _ block.Getter = (*VM)(nil) 67 _ block.Parser = (*VM)(nil) 68 _ block.ChainVM = (*VM)(nil) 69 70 dbPrefixBlockStore = []byte("block-store") 71 dbPrefixStateStore = []byte("state-store") 72 dbPrefixTxIndexer = []byte("tx-indexer") 73 dbPrefixBlockIndexer = []byte("block-indexer") 74 75 proposerAddress = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 76 proposerPubKey = secp256k1.PubKey{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 77 78 errInvalidBlock = errors.New("invalid block") 79 errNoPendingTxs = errors.New("there is no txs to include to block") 80 ) 81 82 type ( 83 AppCreator func(ids.ID) (abciTypes.Application, error) 84 85 VM struct { 86 appCreator AppCreator 87 app proxy.AppConns 88 89 rpcConfig *config.RPCConfig 90 91 log log.Logger 92 chainCtx *snow.Context 93 toEngine chan<- common.Message 94 95 blockStore *store.BlockStore 96 stateStore state.Store 97 state state.State 98 genesis *types.GenesisDoc 99 genChunks []string 100 101 mempool *mempl.CListMempool 102 eventBus *types.EventBus 103 104 txIndexer txindex.TxIndexer 105 blockIndexer indexer.BlockIndexer 106 indexerService *txindex.IndexerService 107 multiGatherer metrics.MultiGatherer 108 109 bootstrapped utils.Atomic[bool] 110 verifiedBlocks map[ids.ID]*Block 111 preferred ids.ID 112 } 113 ) 114 115 func LocalAppCreator(app abciTypes.Application) AppCreator { 116 return func(ids.ID) (abciTypes.Application, error) { 117 return app, nil 118 } 119 } 120 121 func New(appCreator AppCreator) *VM { 122 return &VM{ 123 appCreator: appCreator, 124 app: nil, 125 } 126 } 127 128 // Notify this engine of a request for data from [nodeID]. 129 // 130 // The meaning of [request], and what should be sent in response to it, is 131 // application (VM) specific. 132 // 133 // It is not guaranteed that: 134 // * [request] is well-formed/valid. 135 // 136 // This node should typically send an AppResponse to [nodeID] in response to 137 // a valid message using the same request ID before the deadline. However, 138 // the VM may arbitrarily choose to not send a response to this request. 139 func (vm *VM) AppRequest(ctx context.Context, nodeID ids.NodeID, requestID uint32, deadline time.Time, request []byte) error { 140 panic("implement me") 141 } 142 143 // Notify this engine that an AppRequest message it sent to [nodeID] with 144 // request ID [requestID] failed. 145 // 146 // This may be because the request timed out or because the message couldn't 147 // be sent to [nodeID]. 148 // 149 // It is guaranteed that: 150 // * This engine sent a request to [nodeID] with ID [requestID]. 151 // * AppRequestFailed([nodeID], [requestID]) has not already been called. 152 // * AppResponse([nodeID], [requestID]) has not already been called. 153 func (vm *VM) AppRequestFailed(ctx context.Context, nodeID ids.NodeID, requestID uint32) error { 154 panic("implement me") 155 } 156 157 // Notify this engine of a response to the AppRequest message it sent to 158 // [nodeID] with request ID [requestID]. 159 // 160 // The meaning of [response] is application (VM) specifc. 161 // 162 // It is guaranteed that: 163 // * This engine sent a request to [nodeID] with ID [requestID]. 164 // * AppRequestFailed([nodeID], [requestID]) has not already been called. 165 // * AppResponse([nodeID], [requestID]) has not already been called. 166 // 167 // It is not guaranteed that: 168 // * [response] contains the expected response 169 // * [response] is well-formed/valid. 170 // 171 // If [response] is invalid or not the expected response, the VM chooses how 172 // to react. For example, the VM may send another AppRequest, or it may give 173 // up trying to get the requested information. 174 func (vm *VM) AppResponse(ctx context.Context, nodeID ids.NodeID, requestID uint32, response []byte) error { 175 panic("implement me") 176 } 177 178 // Notify this engine of a gossip message from [nodeID]. 179 // 180 // The meaning of [msg] is application (VM) specific, and the VM defines how 181 // to react to this message. 182 // 183 // This message is not expected in response to any event, and it does not 184 // need to be responded to. 185 // 186 // A node may gossip the same message multiple times. That is, 187 // AppGossip([nodeID], [msg]) may be called multiple times. 188 func (vm *VM) AppGossip(ctx context.Context, nodeID ids.NodeID, msg []byte) error { 189 panic("implement me") 190 } 191 192 // CrossChainAppRequest Notify this engine of a request for data from 193 // [chainID]. 194 // 195 // The meaning of [request], and what should be sent in response to it, is 196 // application (VM) specific. 197 // 198 // Guarantees surrounding the request are specific to the implementation of 199 // the requesting VM. For example, the request may or may not be guaranteed 200 // to be well-formed/valid depending on the implementation of the requesting 201 // VM. 202 // 203 // This node should typically send a CrossChainAppResponse to [chainID] in 204 // response to a valid message using the same request ID before the 205 // deadline. However, the VM may arbitrarily choose to not send a response 206 // to this request. 207 func (vm *VM) CrossChainAppRequest(ctx context.Context, chainID ids.ID, requestID uint32, deadline time.Time, request []byte) error { 208 panic("implement me") 209 } 210 211 // CrossChainAppRequestFailed notifies this engine that a 212 // CrossChainAppRequest message it sent to [chainID] with request ID 213 // [requestID] failed. 214 // 215 // This may be because the request timed out or because the message couldn't 216 // be sent to [chainID]. 217 // 218 // It is guaranteed that: 219 // * This engine sent a request to [chainID] with ID [requestID]. 220 // * CrossChainAppRequestFailed([chainID], [requestID]) has not already been 221 // called. 222 // * CrossChainAppResponse([chainID], [requestID]) has not already been 223 // called. 224 func (vm *VM) CrossChainAppRequestFailed(ctx context.Context, chainID ids.ID, requestID uint32) error { 225 panic("implement me") 226 } 227 228 // CrossChainAppResponse notifies this engine of a response to the 229 // CrossChainAppRequest message it sent to [chainID] with request ID 230 // [requestID]. 231 // 232 // The meaning of [response] is application (VM) specific. 233 // 234 // It is guaranteed that: 235 // * This engine sent a request to [chainID] with ID [requestID]. 236 // * CrossChainAppRequestFailed([chainID], [requestID]) has not already been 237 // called. 238 // * CrossChainAppResponse([chainID], [requestID]) has not already been 239 // called. 240 // 241 // Guarantees surrounding the response are specific to the implementation of 242 // the responding VM. For example, the response may or may not be guaranteed 243 // to be well-formed/valid depending on the implementation of the requesting 244 // VM. 245 // 246 // If [response] is invalid or not the expected response, the VM chooses how 247 // to react. For example, the VM may send another CrossChainAppRequest, or 248 // it may give up trying to get the requested information. 249 func (vm *VM) CrossChainAppResponse(ctx context.Context, chainID ids.ID, requestID uint32, response []byte) error { 250 panic("implement me") 251 } 252 253 // HealthCheck returns health check results and, if not healthy, a non-nil 254 // error 255 // 256 // It is expected that the results are json marshallable. 257 func (vm *VM) HealthCheck(context.Context) (interface{}, error) { 258 return nil, nil 259 } 260 261 // Connector represents a handler that is called when a connection is marked as connected 262 func (vm *VM) Connected(ctx context.Context, nodeID ids.NodeID, nodeVersion *version.Application) error { 263 vm.log.Info("connected", "nodeID", nodeID.String(), "nodeVersion", nodeVersion.String()) 264 return nil 265 } 266 267 // Connector represents a handler that is called when a connection is marked as disconnected 268 func (vm *VM) Disconnected(ctx context.Context, nodeID ids.NodeID) error { 269 vm.log.Info("disconnected", "nodeID", nodeID.String()) 270 return nil 271 } 272 273 // Initialize this VM. 274 // [chainCtx]: Metadata about this VM. 275 // 276 // [chainCtx.networkID]: The ID of the network this VM's chain is 277 // running on. 278 // [chainCtx.chainID]: The unique ID of the chain this VM is running on. 279 // [chainCtx.Log]: Used to log messages 280 // [chainCtx.NodeID]: The unique staker ID of this node. 281 // [chainCtx.Lock]: A Read/Write lock shared by this VM and the 282 // consensus engine that manages this VM. The write 283 // lock is held whenever code in the consensus engine 284 // calls the VM. 285 // 286 // [dbManager]: The manager of the database this VM will persist data to. 287 // [genesisBytes]: The byte-encoding of the genesis information of this 288 // 289 // VM. The VM uses it to initialize its state. For 290 // example, if this VM were an account-based payments 291 // system, `genesisBytes` would probably contain a genesis 292 // transaction that gives coins to some accounts, and this 293 // transaction would be in the genesis block. 294 // 295 // [toEngine]: The channel used to send messages to the consensus engine. 296 // [fxs]: Feature extensions that attach to this VM. 297 func (vm *VM) Initialize( 298 ctx context.Context, 299 chainCtx *snow.Context, 300 dbManager manager.Manager, 301 genesisBytes []byte, 302 upgradeBytes []byte, 303 configBytes []byte, 304 toEngine chan<- common.Message, 305 fxs []*common.Fx, 306 appSender common.AppSender, 307 ) error { 308 vm.chainCtx = chainCtx 309 vm.toEngine = toEngine 310 vm.log = log.NewTMLogger(vm.chainCtx.Log).With("module", "vm") 311 vm.verifiedBlocks = make(map[ids.ID]*Block) 312 vm.rpcConfig = config.DefaultRPCConfig() 313 314 db := dbManager.Current().Database 315 316 dbBlockStore := NewDB(prefixdb.NewNested(dbPrefixBlockStore, db)) 317 vm.blockStore = store.NewBlockStore(dbBlockStore) 318 319 dbStateStore := NewDB(prefixdb.NewNested(dbPrefixStateStore, db)) 320 vm.stateStore = state.NewStore(dbStateStore) 321 322 app, err := vm.appCreator(chainCtx.ChainID) 323 if err != nil { 324 return err 325 } 326 327 vm.state, vm.genesis, err = node.LoadStateFromDBOrGenesisDocProvider( 328 dbStateStore, 329 NewLocalGenesisDocProvider(genesisBytes), 330 ) 331 if err != nil { 332 return nil 333 } 334 for i := 0; i < len(genesisBytes); i += genesisChunkSize { 335 end := i + genesisChunkSize 336 if end > len(genesisBytes) { 337 end = len(genesisBytes) 338 } 339 vm.genChunks = append(vm.genChunks, base64.StdEncoding.EncodeToString(genesisBytes[i:end])) 340 } 341 342 vm.app, err = node.CreateAndStartProxyAppConns(proxy.NewLocalClientCreator(app), vm.log) 343 if err != nil { 344 return err 345 } 346 347 vm.eventBus, err = node.CreateAndStartEventBus(vm.log) 348 if err != nil { 349 return err 350 } 351 352 dbTxIndexer := NewDB(prefixdb.NewNested(dbPrefixTxIndexer, db)) 353 vm.txIndexer = txidxkv.NewTxIndex(dbTxIndexer) 354 355 dbBlockIndexer := NewDB(prefixdb.NewNested(dbPrefixBlockIndexer, db)) 356 vm.blockIndexer = blockidxkv.New(dbBlockIndexer) 357 358 vm.indexerService = txindex.NewIndexerService(vm.txIndexer, vm.blockIndexer, vm.eventBus) 359 vm.indexerService.SetLogger(vm.log.With("module", "indexer")) 360 if err := vm.indexerService.Start(); err != nil { 361 return err 362 } 363 364 handshaker := consensus.NewHandshaker( 365 vm.stateStore, 366 vm.state, 367 vm.blockStore, 368 vm.genesis, 369 ) 370 handshaker.SetLogger(vm.log.With("module", "consensus")) 371 handshaker.SetEventBus(vm.eventBus) 372 if err := handshaker.Handshake(vm.app); err != nil { 373 return fmt.Errorf("error during handshake: %v", err) 374 } 375 376 vm.state, err = vm.stateStore.Load() 377 if err != nil { 378 return nil 379 } 380 381 vm.mempool = mempl.NewCListMempool( 382 config.DefaultMempoolConfig(), 383 vm.app.Mempool(), 384 vm.state.LastBlockHeight, 385 vm, 386 mempl.WithMetrics(mempl.NopMetrics()), 387 mempl.WithPreCheck(state.TxPreCheck(vm.state)), 388 mempl.WithPostCheck(state.TxPostCheck(vm.state)), 389 ) 390 vm.mempool.SetLogger(vm.log.With("module", "mempool")) 391 vm.mempool.EnableTxsAvailable() 392 393 vm.multiGatherer = metrics.NewMultiGatherer() 394 if err := vm.chainCtx.Metrics.Register(vm.multiGatherer); err != nil { 395 return err 396 } 397 398 if vm.state.LastBlockHeight == 0 { 399 block, _ := vm.state.MakeBlock(1, types.Txs{}, makeCommit(1, time.Now()), nil, proposerAddress) 400 block.LastBlockID = types.BlockID{ 401 Hash: tmhash.Sum([]byte{}), 402 PartSetHeader: types.PartSetHeader{ 403 Total: 0, 404 Hash: tmhash.Sum([]byte{}), 405 }, 406 } 407 if err := NewBlock(vm, block, choices.Processing).Accept(ctx); err != nil { 408 return err 409 } 410 } 411 412 vm.log.Info("vm initialization completed") 413 return nil 414 } 415 416 func (vm *VM) NotifyBlockReady() { 417 select { 418 case vm.toEngine <- common.PendingTxs: 419 vm.log.Debug("notify consensys engine") 420 default: 421 vm.log.Error("failed to push PendingTxs notification to the consensus engine.") 422 } 423 } 424 425 // SetState communicates to VM its next state it starts 426 func (vm *VM) SetState(ctx context.Context, state snow.State) error { 427 vm.log.Debug("set state", "state", state.String()) 428 switch state { 429 case snow.Bootstrapping: 430 vm.bootstrapped.Set(false) 431 case snow.NormalOp: 432 vm.bootstrapped.Set(true) 433 default: 434 return snow.ErrUnknownState 435 } 436 return nil 437 } 438 439 // Shutdown is called when the node is shutting down. 440 func (vm *VM) Shutdown(context.Context) error { 441 vm.log.Debug("shutdown start") 442 443 if err := vm.indexerService.Stop(); err != nil { 444 return fmt.Errorf("error closing indexerService: %w ", err) 445 } 446 447 if err := vm.eventBus.Stop(); err != nil { 448 return fmt.Errorf("error closing eventBus: %w ", err) 449 } 450 451 if err := vm.app.Stop(); err != nil { 452 return fmt.Errorf("error closing app: %w ", err) 453 } 454 455 if err := vm.stateStore.Close(); err != nil { 456 return fmt.Errorf("error closing stateStore: %w ", err) 457 } 458 459 if err := vm.blockStore.Close(); err != nil { 460 return fmt.Errorf("Error closing blockStore: %w ", err) 461 } 462 463 vm.log.Debug("shutdown completed") 464 return nil 465 } 466 467 // Version returns the version of the VM. 468 func (vm *VM) Version(context.Context) (string, error) { 469 return Version.String(), nil 470 } 471 472 // Creates the HTTP handlers for custom VM network calls. 473 // 474 // This exposes handlers that the outside world can use to communicate with 475 // a static reference to the VM. Each handler has the path: 476 // [Address of node]/ext/VM/[VM ID]/[extension] 477 // 478 // Returns a mapping from [extension]s to HTTP handlers. 479 // 480 // Each extension can specify how locking is managed for convenience. 481 // 482 // For example, it might make sense to have an extension for creating 483 // genesis bytes this VM can interpret. 484 // 485 // Note: If this method is called, no other method will be called on this VM. 486 // Each registered VM will have a single instance created to handle static 487 // APIs. This instance will be handled separately from instances created to 488 // service an instance of a chain. 489 func (vm *VM) CreateStaticHandlers(context.Context) (map[string]*common.HTTPHandler, error) { 490 // ToDo: need to add implementation 491 return nil, nil 492 } 493 494 // Creates the HTTP handlers for custom chain network calls. 495 // 496 // This exposes handlers that the outside world can use to communicate with 497 // the chain. Each handler has the path: 498 // [Address of node]/ext/bc/[chain ID]/[extension] 499 // 500 // Returns a mapping from [extension]s to HTTP handlers. 501 // 502 // Each extension can specify how locking is managed for convenience. 503 // 504 // For example, if this VM implements an account-based payments system, 505 // it have an extension called `accounts`, where clients could get 506 // information about their accounts. 507 func (vm *VM) CreateHandlers(context.Context) (map[string]*common.HTTPHandler, error) { 508 return map[string]*common.HTTPHandler{ 509 "/rpc": { 510 LockOptions: common.WriteLock, 511 Handler: rpcserver.MakeJSONRPCHandler( 512 NewServiceAsRPCRoutes(vm), 513 vm.log.With("module", "rpc"), 514 ), 515 }, 516 }, nil 517 } 518 519 // Attempt to load a block. 520 // 521 // If the block does not exist, database.ErrNotFound should be returned. 522 // 523 // It is expected that blocks that have been successfully verified should be 524 // returned correctly. It is also expected that blocks that have been 525 // accepted by the consensus engine should be able to be fetched. It is not 526 // required for blocks that have been rejected by the consensus engine to be 527 // able to be fetched. 528 func (vm *VM) GetBlock(ctx context.Context, blkID ids.ID) (snowman.Block, error) { 529 vm.log.Debug("get block", "blkID", blkID.String()) 530 if b, ok := vm.verifiedBlocks[blkID]; ok { 531 vm.log.Debug("get block", "status", b.Status()) 532 return b, nil 533 } 534 b := vm.blockStore.LoadBlockByHash(blkID[:]) 535 if b == nil { 536 return nil, errInvalidBlock 537 } 538 vm.log.Debug("get block", "status", choices.Accepted) 539 return NewBlock(vm, b, choices.Accepted), nil 540 } 541 542 // Attempt to create a block from a stream of bytes. 543 // 544 // The block should be represented by the full byte array, without extra 545 // bytes. 546 // 547 // It is expected for all historical blocks to be parseable. 548 func (vm *VM) ParseBlock(ctx context.Context, blockBytes []byte) (snowman.Block, error) { 549 vm.log.Debug("parse block") 550 551 protoBlock := new(tmproto.Block) 552 if err := protoBlock.Unmarshal(blockBytes[1:]); err != nil { 553 vm.log.Error("can't parse block", "err", err) 554 return nil, err 555 } 556 557 block, err := types.BlockFromProto(protoBlock) 558 if err != nil { 559 vm.log.Error("can't create block from proto", "err", err) 560 return nil, err 561 } 562 563 blk := NewBlock(vm, block, choices.Status(uint32(blockBytes[0]))) 564 vm.log.Debug("parsed block", "id", blk.ID(), "status", blk.Status().String()) 565 if _, ok := vm.verifiedBlocks[blk.ID()]; !ok { 566 vm.verifiedBlocks[blk.ID()] = blk 567 } 568 569 return blk, nil 570 } 571 572 // Attempt to create a new block from data contained in the VM. 573 // 574 // If the VM doesn't want to issue a new block, an error should be 575 // returned. 576 func (vm *VM) BuildBlock(ctx context.Context) (snowman.Block, error) { 577 vm.log.Debug("build block") 578 579 txs := vm.mempool.ReapMaxBytesMaxGas(-1, -1) 580 if len(txs) == 0 { 581 return nil, errNoPendingTxs 582 } 583 584 state := vm.state.Copy() 585 586 var preferredBlock *types.Block 587 if vm.preferred != ids.Empty { 588 if b, ok := vm.verifiedBlocks[vm.preferred]; ok { 589 vm.log.Debug("load preferred block from cache", "id", vm.preferred.String()) 590 preferredBlock = b.Block 591 } else { 592 vm.log.Debug("load preferred block from blockStore", "id", vm.preferred.String()) 593 preferredBlock = vm.blockStore.LoadBlockByHash(vm.preferred[:]) 594 if preferredBlock == nil { 595 return nil, errInvalidBlock 596 } 597 } 598 } else { 599 preferredBlock = vm.blockStore.LoadBlockByHash(state.LastBlockID.Hash) 600 } 601 preferredHeight := preferredBlock.Header.Height 602 603 commit := makeCommit(preferredHeight+1, time.Now()) 604 block, _ := state.MakeBlock(preferredHeight+1, txs, commit, nil, proposerAddress) 605 block.LastBlockID = types.BlockID{ 606 Hash: preferredBlock.Hash(), 607 PartSetHeader: preferredBlock.MakePartSet(types.BlockPartSizeBytes).Header(), 608 } 609 610 blk := NewBlock(vm, block, choices.Processing) 611 vm.verifiedBlocks[blk.ID()] = blk 612 613 vm.log.Debug("build block", "id", blk.ID(), "height", blk.Height(), "txs", len(block.Txs)) 614 return blk, nil 615 } 616 617 // Notify the VM of the currently preferred block. 618 // 619 // This should always be a block that has no children known to consensus. 620 func (vm *VM) SetPreference(ctx context.Context, blkID ids.ID) error { 621 vm.log.Debug("set preference", "blkID", blkID.String()) 622 vm.preferred = blkID 623 return nil 624 } 625 626 // LastAccepted returns the ID of the last accepted block. 627 // 628 // If no blocks have been accepted by consensus yet, it is assumed there is 629 // a definitionally accepted block, the Genesis block, that will be 630 // returned. 631 func (vm *VM) LastAccepted(context.Context) (ids.ID, error) { 632 if vm.preferred == ids.Empty { 633 return ids.ID(vm.state.LastBlockID.Hash), nil 634 } 635 return vm.preferred, nil 636 } 637 638 func (vm *VM) applyBlock(block *Block) error { 639 vm.mempool.Lock() 640 defer vm.mempool.Unlock() 641 642 state := vm.state.Copy() 643 644 err := validateBlock(state, block.Block) 645 if err != nil { 646 return err 647 } 648 649 abciResponses, err := execBlockOnProxyApp(vm.log, vm.app.Consensus(), block.Block, vm.stateStore, state.InitialHeight) 650 if err != nil { 651 return err 652 } 653 654 // Save the results before we commit. 655 if err := vm.stateStore.SaveABCIResponses(block.Block.Height, abciResponses); err != nil { 656 return err 657 } 658 659 blockID := types.BlockID{ 660 Hash: block.Block.Hash(), 661 PartSetHeader: block.Block.MakePartSet(types.BlockPartSizeBytes).Header(), 662 } 663 664 // while mempool is Locked, flush to ensure all async requests have completed 665 // in the ABCI app before Commit. 666 if err := vm.mempool.FlushAppConn(); err != nil { 667 vm.log.Error("client error during mempool.FlushAppConn", "err", err) 668 return err 669 } 670 671 // Commit block, get hash back 672 res, err := vm.app.Consensus().CommitSync() 673 if err != nil { 674 vm.log.Error("client error during proxyAppConn.CommitSync", "err", err) 675 return err 676 } 677 678 // Update the state with the block and responses. 679 state.LastBlockHeight = block.Block.Height 680 state.LastBlockID = blockID 681 state.LastBlockTime = block.Time 682 state.LastResultsHash = types.NewResults(abciResponses.DeliverTxs).Hash() 683 state.AppHash = res.Data 684 685 // ResponseCommit has no error code - just data 686 vm.log.Info( 687 "committed state", 688 "height", block.Height, 689 "num_txs", len(block.Block.Txs), 690 "app_hash", fmt.Sprintf("%X", res.Data), 691 ) 692 693 deliverTxResponses := make([]*abciTypes.ResponseDeliverTx, len(block.Block.Txs)) 694 for i := range block.Block.Txs { 695 deliverTxResponses[i] = &abciTypes.ResponseDeliverTx{Code: abciTypes.CodeTypeOK} 696 } 697 698 // Update mempool. 699 if err := vm.mempool.Update( 700 block.Block.Height, 701 block.Block.Txs, 702 deliverTxResponses, 703 TxPreCheck(state), 704 TxPostCheck(state), 705 ); err != nil { 706 return err 707 } 708 709 if err := vm.stateStore.Save(state); err != nil { 710 return err 711 } 712 vm.state = state 713 714 vm.blockStore.SaveBlock(block.Block, block.Block.MakePartSet(types.BlockPartSizeBytes), block.Block.LastCommit) 715 fireEvents(vm.log, vm.eventBus, block.Block, abciResponses) 716 return nil 717 }