github.com/MetalBlockchain/metalgo@v1.11.9/vms/example/xsvm/chain/chain.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package chain 5 6 import ( 7 "github.com/MetalBlockchain/metalgo/database" 8 "github.com/MetalBlockchain/metalgo/ids" 9 "github.com/MetalBlockchain/metalgo/snow" 10 "github.com/MetalBlockchain/metalgo/snow/choices" 11 "github.com/MetalBlockchain/metalgo/vms/example/xsvm/state" 12 13 xsblock "github.com/MetalBlockchain/metalgo/vms/example/xsvm/block" 14 ) 15 16 var _ Chain = (*chain)(nil) 17 18 type Chain interface { 19 LastAccepted() ids.ID 20 SetChainState(state snow.State) 21 GetBlock(blkID ids.ID) (Block, error) 22 23 // Creates a fully verifiable and executable block, which can be processed 24 // by the consensus engine, from a stateless block. 25 NewBlock(blk *xsblock.Stateless) (Block, error) 26 } 27 28 type chain struct { 29 chainContext *snow.Context 30 acceptedState database.Database 31 32 // chain state as driven by the consensus engine 33 chainState snow.State 34 35 lastAccepted ids.ID 36 verifiedBlocks map[ids.ID]*block 37 } 38 39 func New(ctx *snow.Context, db database.Database) (Chain, error) { 40 // Load the last accepted block data. For a newly created VM, this will be 41 // the genesis. It is assumed the genesis was processed and stored 42 // previously during VM initialization. 43 lastAcceptedID, err := state.GetLastAccepted(db) 44 if err != nil { 45 return nil, err 46 } 47 48 c := &chain{ 49 chainContext: ctx, 50 acceptedState: db, 51 lastAccepted: lastAcceptedID, 52 } 53 54 lastAccepted, err := c.getBlock(lastAcceptedID) 55 c.verifiedBlocks = map[ids.ID]*block{ 56 lastAcceptedID: lastAccepted, 57 } 58 return c, err 59 } 60 61 func (c *chain) LastAccepted() ids.ID { 62 return c.lastAccepted 63 } 64 65 func (c *chain) SetChainState(state snow.State) { 66 c.chainState = state 67 } 68 69 func (c *chain) GetBlock(blkID ids.ID) (Block, error) { 70 return c.getBlock(blkID) 71 } 72 73 func (c *chain) NewBlock(blk *xsblock.Stateless) (Block, error) { 74 blkID, err := blk.ID() 75 if err != nil { 76 return nil, err 77 } 78 79 if blk, exists := c.verifiedBlocks[blkID]; exists { 80 return blk, nil 81 } 82 83 blkBytes, err := xsblock.Codec.Marshal(xsblock.CodecVersion, blk) 84 if err != nil { 85 return nil, err 86 } 87 88 return &block{ 89 Stateless: blk, 90 chain: c, 91 id: blkID, 92 bytes: blkBytes, 93 }, nil 94 } 95 96 func (c *chain) getBlock(blkID ids.ID) (*block, error) { 97 if blk, exists := c.verifiedBlocks[blkID]; exists { 98 return blk, nil 99 } 100 101 blkBytes, err := state.GetBlock(c.acceptedState, blkID) 102 if err != nil { 103 return nil, err 104 } 105 106 stateless, err := xsblock.Parse(blkBytes) 107 if err != nil { 108 return nil, err 109 } 110 return &block{ 111 Stateless: stateless, 112 chain: c, 113 id: blkID, 114 status: choices.Accepted, 115 bytes: blkBytes, 116 }, nil 117 }