github.com/ava-labs/avalanchego@v1.11.11/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/ava-labs/avalanchego/database" 8 "github.com/ava-labs/avalanchego/ids" 9 "github.com/ava-labs/avalanchego/snow" 10 "github.com/ava-labs/avalanchego/vms/example/xsvm/state" 11 12 xsblock "github.com/ava-labs/avalanchego/vms/example/xsvm/block" 13 ) 14 15 var _ Chain = (*chain)(nil) 16 17 type Chain interface { 18 LastAccepted() ids.ID 19 SetChainState(state snow.State) 20 GetBlock(blkID ids.ID) (Block, error) 21 22 // Creates a fully verifiable and executable block, which can be processed 23 // by the consensus engine, from a stateless block. 24 NewBlock(blk *xsblock.Stateless) (Block, error) 25 } 26 27 type chain struct { 28 chainContext *snow.Context 29 acceptedState database.Database 30 31 // chain state as driven by the consensus engine 32 chainState snow.State 33 34 lastAcceptedID ids.ID 35 lastAcceptedHeight uint64 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 lastAcceptedID: lastAcceptedID, 52 } 53 54 lastAccepted, err := c.getBlock(lastAcceptedID) 55 if err != nil { 56 return nil, err 57 } 58 59 c.lastAcceptedHeight = lastAccepted.Height() 60 c.verifiedBlocks = map[ids.ID]*block{ 61 lastAcceptedID: lastAccepted, 62 } 63 return c, err 64 } 65 66 func (c *chain) LastAccepted() ids.ID { 67 return c.lastAcceptedID 68 } 69 70 func (c *chain) SetChainState(state snow.State) { 71 c.chainState = state 72 } 73 74 func (c *chain) GetBlock(blkID ids.ID) (Block, error) { 75 return c.getBlock(blkID) 76 } 77 78 func (c *chain) NewBlock(blk *xsblock.Stateless) (Block, error) { 79 blkID, err := blk.ID() 80 if err != nil { 81 return nil, err 82 } 83 84 if blk, exists := c.verifiedBlocks[blkID]; exists { 85 return blk, nil 86 } 87 88 blkBytes, err := xsblock.Codec.Marshal(xsblock.CodecVersion, blk) 89 if err != nil { 90 return nil, err 91 } 92 93 return &block{ 94 Stateless: blk, 95 chain: c, 96 id: blkID, 97 bytes: blkBytes, 98 }, nil 99 } 100 101 func (c *chain) getBlock(blkID ids.ID) (*block, error) { 102 if blk, exists := c.verifiedBlocks[blkID]; exists { 103 return blk, nil 104 } 105 106 blkBytes, err := state.GetBlock(c.acceptedState, blkID) 107 if err != nil { 108 return nil, err 109 } 110 111 stateless, err := xsblock.Parse(blkBytes) 112 if err != nil { 113 return nil, err 114 } 115 return &block{ 116 Stateless: stateless, 117 chain: c, 118 id: blkID, 119 bytes: blkBytes, 120 }, nil 121 }