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  }